更改没有动画的切换状态

ale*_*lex 30 android android-listview android-switch

在我的Android项目中,我有一个ListView包含SwitchCompat项目的行(AppCompat for Switchwidget).

当我滚动到列表并使用视图调用getView(...)方法时,我的问题发生.我重新定义了正确的状态,但动画是可见的.MyAdapterrecycledSwitch

在这种情况下有一个防止动画的解决方案?

在此输入图像描述

小智 52

调用jumpDrawablesToCurrentState()将跳过动画.

  • 我发现这会将开关的颜色改变为活动状态,但它仍然处于"未检查"状态. (3认同)
  • 使用数据绑定,在`jumpDrawablesToCurrentState()`之前调用`executePendingBindings()`。 (2认同)
  • 如果您在列表中滚动,这对单选按钮/复选框很有用。 (2认同)

ale*_*lex 12

我终于找到了一个解决方案,但似乎并不是很干净

ViewGroup viewGroup = (ViewGroup) view; // the recycled view
viewGroup.removeView(switch);
switch.setChecked(states[index]);
viewGroup.addView(switch);
Run Code Online (Sandbox Code Playgroud)

如果存在更好的解决方案,请分享.

  • @kcoppock,这个代码在SwitchCompat中被改为`if(isAttachedToWindow()&& isLaidOut()&& isShown())`所以可以暂时隐藏它:`switch.setVisibility(View.INVISIBLE); switch.setChecked(); switch.setVisibility(View.VISIBLE);` (4认同)
  • 不幸的是,你的方式似乎是唯一的.在API 21`Tlock`中查看`setChecked()`的代码:`if(isAttachedToWindow()&& isLaidOut()){animateThumbToCheckedState(checked); }` (3认同)

Rol*_*f ツ 5

我有同样的问题,我设法用一些最小的反射来解决它.

用法:

要在没有动画的情况下更改开关状态,请setChecked(boolean checked, boolean animate)为animate参数调用false方法.如果此方法在调用此方法时动画已经动画,则动画将停止并且开关跳转到所需位置.

SwitchCompatFix.java

import android.content.Context;
import android.support.v7.widget.SwitchCompat;
import android.util.AttributeSet;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Work around for: http://stackoverflow.com/questions/27139262/change-switch-state-without-animation
 * Possible fix for bug 101107: https://code.google.com/p/android/issues/detail?id=101107
 *
 * Version 0.2
 * @author Rolf Smit
 */
public class SwitchCompatFix extends SwitchCompat {

    public SwitchCompatFix(Context context) {
        super(context);
        initHack();
    }

    public SwitchCompatFix(Context context, AttributeSet attrs) {
        super(context, attrs);
        initHack();
    }

    public SwitchCompatFix(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initHack();
    }

    private Method methodCancelPositionAnimator = null;
    private Method methodSetThumbPosition = null;

    private void initHack(){
        try {
            methodCancelPositionAnimator = SwitchCompat.class.getDeclaredMethod("cancelPositionAnimator");
            methodSetThumbPosition = SwitchCompat.class.getDeclaredMethod("setThumbPosition", float.class);
            methodCancelPositionAnimator.setAccessible(true);
            methodSetThumbPosition.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public void setChecked(boolean checked, boolean animate){
        // Java does not support super.super.xxx calls, a call to the SwitchCompat default setChecked method is needed.
        super.setChecked(checked);
        if(!animate) {

            // See original SwitchCompat source:
            // Calling the super method may result in setChecked() getting called
            // recursively with a different value, so load the REAL value...
            checked = isChecked();

            // Cancel any running animations (started by super.setChecked()) and immediately move the thumb to the new position
            try {
                if(methodCancelPositionAnimator != null && methodSetThumbPosition != null) {
                    methodCancelPositionAnimator.invoke(this);
                    methodSetThumbPosition.invoke(this, checked ? 1 : 0);
                }
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于proguard用户的注意事项:

由于此方法使用反射,因此可能需要额外的proguard规则(如果尚未存在).

-keep class android.support.v7.widget.SwitchCompat {
    private void cancelPositionAnimator();
    private void setThumbPosition(float);
}
Run Code Online (Sandbox Code Playgroud)

当您使用以下proguard规则之一(或类似规则)时,不需要此附加规则:

-keep class android.support.v7.widget.** { *; }
-keep class android.support.v7.** { *; }
Run Code Online (Sandbox Code Playgroud)