Уменьшить размер кнопки при нажатии и восстановить ее размер при отпускании
Я хочу создать кнопку, которая меняет размер (немного меньше) при нажатии, и после того, как кнопка будет отпущена, размер должен вернуться к нормальному размеру. Я использую Scale xml, чтобы добиться этого, но он переместился даже если я не отпущу кнопку.
здесь я имею в виду просмотр изображений.
вот мой исходный код:-
imgSpin = (ImageView) findViewById(R.id.iv_spins);
imgSpin.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
imgSpin.startAnimation(mAnimation);
spinslot();
break;
case MotionEvent.ACTION_UP:
imgSpin.clearAnimation();
imgSpin.setEnabled(false);
break;
}
return true;
}
});
мой масштаб Xml:-
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromXScale=".8"
android:fromYScale=".8"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" >
</scale>
мой XML:-
<LinearLayout
android:id="@+id/layout_status"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight=".2"
android:orientation="horizontal" >
<View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5" />
<ImageView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2.1"
android:background="@drawable/bootser" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2.5"
android:background="@drawable/bet_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
android:weightSum="1" >
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight=".2"
android:src="@drawable/leftarrow" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:layout_weight=".6"
android:gravity="center"
android:text="Bet"
android:textColor="@android:color/white" />
<ImageView
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:layout_weight=".2"
android:src="@drawable/rightarrow" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2.5"
android:background="@drawable/container"
android:gravity="center" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="winning"
android:textColor="@android:color/white" />
</LinearLayout>
<ImageView
android:id="@+id/iv_spins"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.9"
android:background="@drawable/spin" />
<View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5" />
</LinearLayout>
Я попытался с paramLayout, но, как я установил вес в XML, чтобы он не дал мне эффект на анимацию.
я уже использую этот подход:-
case MotionEvent.ACTION_DOWN:
ViewGroup.LayoutParams params = imgSpin.getLayoutParams();
// Button new width
params.width = params.width - (params.width *90/100);
imgSpin.setLayoutParams(params);
break;
params.width всегда возвращает мне ноль, поэтому я пытался сделать это с весом, используя вес, мой глюк зрения на клик.. я хочу, чтобы он был гладким, поэтому я предпочитаю масштабирование
Второй подход:-
case MotionEvent.ACTION_DOWN:
LinearLayout.LayoutParams params = (android.widget.LinearLayout.LayoutParams) imgSpin
.getLayoutParams();
// Button new width
params.weight = 1.7f;
imgSpin.setLayoutParams(params);
// imgSpin.startAnimation(mAnimation);
// spinslot();
break;
case MotionEvent.ACTION_UP:
LinearLayout.LayoutParams params2 = (android.widget.LinearLayout.LayoutParams) imgSpin
.getLayoutParams();
// Button new width
params2.weight = 1.9f;
imgSpin.setLayoutParams(params2);
// imgSpin.clearAnimation();
imgSpin.setEnabled(false);
break;
}
return true;
это работает, но не гладко
Подскажите пожалуйста как сделать
Спасибо
9 ответов
Вот что вы хотите:-
imgSpin.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
ObjectAnimator scaleDownX = ObjectAnimator.ofFloat(imgSpin,
"scaleX", 0.8f);
ObjectAnimator scaleDownY = ObjectAnimator.ofFloat(imgSpin,
"scaleY", 0.8f);
scaleDownX.setDuration(1000);
scaleDownY.setDuration(1000);
AnimatorSet scaleDown = new AnimatorSet();
scaleDown.play(scaleDownX).with(scaleDownY);
scaleDown.start();
spinslot();
break;
case MotionEvent.ACTION_UP:
ObjectAnimator scaleDownX2 = ObjectAnimator.ofFloat(
imgSpin, "scaleX", 1f);
ObjectAnimator scaleDownY2 = ObjectAnimator.ofFloat(
imgSpin, "scaleY", 1f);
scaleDownX2.setDuration(1000);
scaleDownY2.setDuration(1000);
AnimatorSet scaleDown2 = new AnimatorSet();
scaleDown2.play(scaleDownX2).with(scaleDownY2);
scaleDown2.start();
imgSpin.setEnabled(false);
break;
}
return true;
}
});
И просто внесите несколько изменений в ваш XML:
<ImageView
android:id="@+id/iv_spins"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.9"
android:adjustViewBounds="true"
android:background="@drawable/spin"
android:scaleX="1"
android:scaleY="1" />
используйте scaleDown.play (scaleDownX).with (scaleDownY), он сохранит анимированную позицию и не вернет ее к исходному
Надеюсь, это решит ваши проблемы
Android Best Practice (для вашего требования):
1- Создайте два XML-файла в /res/animator
я. reduce_size.xml
<?xml version="1.0" encoding="utf-8"?>
<set android:ordering="sequentially"
xmlns:android="http://schemas.android.com/apk/res/android">
<set>
<objectAnimator
android:propertyName="scaleX"
android:duration="300"
android:valueTo="0.9f"
android:valueType="floatType"/>
<objectAnimator
android:propertyName="scaleY"
android:duration="300"
android:valueTo="0.9f"
android:valueType="floatType"/>
</set>
</set>
II. regain_size.xml
<?xml version="1.0" encoding="utf-8"?>
<set android:ordering="sequentially"
xmlns:android="http://schemas.android.com/apk/res/android">
<set>
<objectAnimator
android:propertyName="scaleX"
android:duration="1000"
android:valueTo="1f"
android:startOffset="300"
android:valueType="floatType"/>
<objectAnimator
android:propertyName="scaleY"
android:duration="1000"
android:valueTo="1f"
android:startOffset="300"
android:valueType="floatType"/>
</set>
</set>
2- Использование
я. Когда MotionEvent.ACTION_DOWN
AnimatorSet reducer = (AnimatorSet) AnimatorInflater.loadAnimator(mContext,R.animator.squeeze_in);
reducer.setTarget(view);
reducer.start();
II. Когда MotionEvent.ACTION_UP
AnimatorSet regainer = (AnimatorSet) AnimatorInflater.loadAnimator(mContext,R.animator.squeeze_out);
regainer.setTarget(view);
regainer.start();
Это решение тщательно протестировано и соответствует вашим требованиям.
Начиная с API 21 (Lollipop) доступно только xml-решение на основе атрибута stateListAnimator. Вот пример макета, который при нажатии масштабируется до 0,9 от исходного размера:
<!-- res/layout/my_layout.xml -->
<LinearLayout ...
android:stateListAnimator="@animator/zoom_out_animator">...</layout>
<!-- res/animator/zoom_out_animator -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<set>
<objectAnimator
android:propertyName="scaleX"
android:valueTo="1.0"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
<objectAnimator
android:propertyName="scaleY"
android:valueTo="1.0"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</set>
</item>
<item android:state_pressed="true">
<set>
<objectAnimator
android:propertyName="scaleX"
android:valueTo="0.9"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
<objectAnimator
android:propertyName="scaleY"
android:valueTo="0.9"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</set>
</item>
</selector>
Вы также можете найти пример в официальном приложении с образцами материалов Owl. Взгляните на onboarding_topic_item.xml.
Несколько похожих вопросов:
Вы можете сделать это программно следующим образом на TouchListener
new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction == MotionEvent.ACTION_DOWN) {
// scale your value
float reducedvalue = (float)0.7;
v.setScaleX(reducedvalue);
v.setScaleY(reducedvalue);
}
else if (event.getAction == MotionEvent.ACTION_UP) {
v.setScaleX(1);
v.setScaleY(1);
}
}
}
Это очень просто, но вы должны знать, как Android API обрабатывает вызов каждого слушателя.
Вот уловка:
1- метод onTouch в TouchListener будет вызываться первым.
1.1- Если метод onTouch возвращает true, то onLongClick(в LongClickListener) или onClick(в ClickListener) будут проигнорированы (оба больше не будут вызываться).
2- Если onTouch метод возвращает ложь, а затем проверить, если onLongClick возвращает истину, так OnClick не будет называться, но если она возвращает ложь так OnClick будет называться так же.
Вот пример:
targetButton.setOnLongClickListener(v -> {
targetButton.animate().scaleX(1.2f).scaleY(1.2f).setDuration(0);
Log.d("Button", "onLong: ");
return true;
});
targetButton.setOnClickListener(v -> {
Log.d("Button", "onClick: ");
});
targetButton.setOnTouchListener((v, event) -> {
Log.d("Button", "onTouch: ");
if (event.getAction() == MotionEvent.ACTION_UP) {
recordButton.animate().scaleX(1.0f).scaleY(1.0f).setDuration(0);
}
// if you want to make it pretty increase the size when click also
/* else if (event.getAction() == MotionEvent.ACTION_DOWN) {
targetButton.animate().scaleX(1.2f).scaleY(1.2f).setDuration(0);
} */
return false;
});
В этом примере я пытаюсь увеличить размер кнопки, если я обнаруживаю долгое нажатие, в противном случае я делаю что-то в методе onClick, и если пользователь отпускает кнопку, я снова уменьшаю размер.
Если вы хотите, чтобы onClick вызывался каждый раз, когда вызывается onLongClick, просто сделайте так, чтобы onLongClick возвращал false;
Вы можете добавить свойство fillafter: android:fillAfter="true"
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromXScale=".8"
android:fromYScale=".8"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="true"
android:toXScale="1.0"
android:toYScale="1.0" >
</scale>
Котлин Решение
- Создать функцию расширения:
fun View.addElasticTouchEffect() { this.setOnTouchListener { view, motionEvent -> when (motionEvent.action) { MotionEvent.ACTION_DOWN -> { this.animate().scaleX(0.96f).scaleY(0.96f).setDuration(100).start() } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { this.animate().scaleX(1f).scaleY(1f).setDuration(100).start() if (motionEvent.action == MotionEvent.ACTION_UP) { this.performClick() } } } return@setOnTouchListener true } }
- Вызов созданной функции в представлении:
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding.ivAddress.addElasticTouchEffect() binding.ivAddress.setOnClickListener { // on click } } }
Надеюсь, это помогло вам
<ImageView
android:id="@+id/iv_spins"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.9"
android:adjustViewBounds="true"
android:background="@drawable/spin"
android:scaleX="1"
android:scaleY="1"
/>
Вот код, который сработал у меня:
<!--res/animator/scale_pressed.xml-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<set>
<objectAnimator
android:propertyName="scaleX"
android:valueTo="1.0"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
<objectAnimator
android:propertyName="scaleY"
android:valueTo="1.0"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</set>
</item>
<item android:state_pressed="true">
<set>
<objectAnimator
android:propertyName="scaleX"
android:valueTo="0.90"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
<objectAnimator
android:propertyName="scaleY"
android:valueTo="0.90"
android:duration="@android:integer/config_shortAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</set>
</item>
</selector>
В принципе то же самое, что и в ответе Валерия Каткова , но я добавилandroid:state_pressed="false"
без чего в моем случае это не сработало.
И вы можете использовать его так:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
android:stateListAnimator="@animator/scale_pressed"/>
Вот как это выглядит: