【问题标题】:Extending Preference classes in Android Lollipop = losing animation在 Android Lollipop 中扩展 Preference 类 = 丢失动画
【发布时间】:2015-07-31 22:20:46
【问题描述】:

仅用于在 Android Lollipop 上扩展 CheckBoxPreferenceSwitchPreference,小部件(复选框或开关)将不再有动画。

我想扩展 SwitchPreference 以强制 api

我正在使用新的AppCompatPreferenceActivityappcompat-v7:22.1.1,但这似乎不会影响开关。

问题是只扩展这些类,而不添加任何自定义布局或小部件资源布局,动画就消失了。

我知道我可以编写我的preference.xml 的两个实例(在内部值-v21 上)并且它会工作......但我想知道为什么会发生这种情况,如果有人知道没有两个偏好的解决方案.xml。

代码示例:

public class SwitchPreference extends android.preference.SwitchPreference {

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

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

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

    public SwitchPreference(Context context) {
        super(context);
    }
}

CheckBoxPreference 或相同,然后使用:

<com.my.package.SwitchPreference />

将使棒棒糖设备中的动画消失。

--

我为 SwitchPreference(我可以使用 CheckBoxPreference)尝试的另一件事是提供一个具有默认 id 的布局,但 @android:id/switchWidgetis not public@android:id/checkbox 是。我也知道我可以使用 <CheckBoxPreference /> 并提供一个实际上是 SwitchCompat 的小部件布局,但我想避免这种情况(混淆名称)。

【问题讨论】:

标签: android android-5.0-lollipop android-preferences material-design


【解决方案1】:

我设法像这样修复它,并且动画在它直接进入没有动画的状态之前工作:

修复:

CustomSwitchCompat.class

public class CustomSwitchCompat extends SwitchCompat {

    public CustomSwitchCompat(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean isShown() {
        return getVisibility() == VISIBLE;
    }

}

在你的布局中这样做:preference_switch_layout.xml

<com.example.CustomSwitchCompat
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@android:id/checkbox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@null"
    android:clickable="false"
    android:focusable="false"
    app:switchMinWidth="55dp"/>

并在您的preference.xml 中执行以下操作:

<CheckBoxPreference
   android:defaultValue="false"
   android:key=""
   android:widgetLayout="@layout/preference_switch_layout"
   android:summary=""
   android:title="" />

【讨论】:

    【解决方案2】:

    有时从类扩展并不是最好的解决方案。为了避免丢失动画,您可以改为 Compose 它,我的意思是创建一个具有 SwitchPreference 字段变量的类并将新逻辑应用于它。这就像一个包装。这对我有用。

    【讨论】:

      【解决方案3】:

      看来我找到了解决您问题的方法。

      详尽的解释

      SwitchCompat中,当切换开关时,它会在播放动画之前测试一些功能:getWindowToken() != null &amp;&amp; ViewCompat.isLaidOut(this) &amp;&amp; isShown()

      完整方法:

      @Override
      public void setChecked(boolean checked) {
          super.setChecked(checked);
          // Calling the super method may result in setChecked() getting called
          // recursively with a different value, so load the REAL value...
          checked = isChecked();
          if (getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown()) {
              animateThumbToCheckedState(checked);
          } else {
              // Immediately move the thumb to the new position.
              cancelPositionAnimator();
              setThumbPosition(checked ? 1 : 0);
          }
      }
      

      通过使用扩展SwitchCompat 的自定义视图,我发现isShown() 总是返回false,因为while 的第三次迭代parent == null

      public boolean isShown() {
          View current = this;
          //noinspection ConstantConditions
          do {
              if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) {
                  return false;
              }
              ViewParent parent = current.mParent;
              if (parent == null) {
                  return false; // We are not attached to the view root
              }
              if (!(parent instanceof View)) {
                  return true;
              }
              current = (View) parent;
          } while (current != null);
      
          return false;
      }
      

      有趣的是,第三个父级是 Preference 中传递给 getView(View convertView, ViewGroup parent) 的第二个属性,这意味着 PreferenceGroupAdapter 没有将父级传递给它自己的 getView() .为什么会发生这种情况以及为什么只会发生在自定义首选项类中,我不知道。

      出于测试目的,我使用 CheckBoxPreferenceSwitchCompat 作为widgetLayout,我也没有看到动画。

      修复

      现在解决问题:只需让您自己的视图扩展 SwitchCompat,然后像这样覆盖您的 isShown()

      @Override
      public boolean isShown() {
          return getVisibility() == VISIBLE;
      }
      

      将此SwitchView 用于您的widgetLayout 样式,并且动画再次起作用:D

      样式:

      <style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
          …
          <item name="android:checkBoxPreferenceStyle">@style/Preference.SwitchView</item>
          …
      </style>
      
      <style name="Preference.SwitchView">
          <item name="android:widgetLayout">@layout/preference_switch_view</item>
      </style>
      

      小部件布局:

      <de.Maxr1998.example.preference.SwitchView
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@android:id/checkbox"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:background="@null"
          android:clickable="false"
          android:focusable="false" />
      

      【讨论】:

      • 这听起来很有希望!但是,我确实在我的库(github.com/ferrannp/material-preferences)中尝试了它,但我没有让它工作(在棒棒糖之前没有动画)。你可能有一个工作回购吗? .顺便说一句,我在前棒棒糖上没有得到动画,无论是在开关上还是在复选框上。
      • 动画适用于 Lollipop 及之前的版本。我没有为此设置存储库,无论如何它只是此处列出的代码。顺便说一句,这个解决方案也有一个错误,因为有时会在滚动列表时播放动画。此外,虽然显示正确的颜色,但有时开关的拇指在错误的一侧。..
      【解决方案4】:

      公共类 SwitchPreference 扩展 android.preference.SwitchPreference {

      public SwitchPreference(Context context) {
          this(context, null);
      }
      
      public SwitchPreference(Context context, AttributeSet attrs) {
          this(context, attrs, android.R.attr.checkBoxPreferenceStyle);
      }
      
      public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
          this(context, attrs, defStyleAttr, 0);
      }
      
      public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
          super(context, attrs, defStyleAttr, defStyleRes);
      
          try {
              Field canRecycleLayoutField = Preference.class.getDeclaredField("mCanRecycleLayout");
              canRecycleLayoutField.setAccessible(true);
              canRecycleLayoutField.setBoolean(this, true);
          } catch (NoSuchFieldException e) {
              e.printStackTrace();
          } catch (IllegalAccessException e) {
              e.printStackTrace();
          }
      }
      

      【讨论】:

      • 您好,您能详细说明一下吗?我试过了,我收到了 java.lang.NoSuchFieldException: mCanRecycleLayout 错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-19
      • 2014-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多