Android 进阶之旅

Android 进阶学习(三十五) Android 中给Vi

2022-11-08  本文已影响0人  Tsm_2020

问题回顾

在上一篇博客 Android 进阶学习(二十四) Android 中给View 添加Drawable的思考 的结尾处 ,我说出了一个问题,那就是我自己写的drawable 缓存,缓存的是drawable 本身,这就使得不同的View 在使用相同的drawable时,drawable 不适配的情况,比如 RecyclerView 的item 是一个 水平自动填充的item , 如果上一个使用这个drawable 的item 宽度比当前这个item的宽度宽,就会导致当前这个item 的背景drawable 的宽度超过了item的宽度,出现不适配的情况,那么这种情况 源码是如何解决的呢,

@Nullable
  Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id,
          int density, @Nullable Resources.Theme theme)
          throws NotFoundException {
          ...省略部分代码
          if (!mPreloading && useCache) {
           这里就是获取缓存的drawable
              final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
              if (cachedDrawable != null) {
                  cachedDrawable.setChangingConfigurations(value.changingConfigurations);
                  return cachedDrawable;
              }
          }
        ...省略部分代 
      }
  }

class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> {
  @UnsupportedAppUsage
  public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
      final Drawable.ConstantState entry = get(key, theme);
      if (entry != null) {
          每次都是利用   Drawable.ConstantState 重新创建一个drawable 
          return entry.newDrawable(resources, theme);
      }
      return null;
  }

}

从源码这里我们可以看到,即使使用的是同样的drawable.xml 文件,每个view 的drawable 都是单独创建的,只不过这个模板只创建了一次,所以我们的缓存也需要缓存 Drawable.ConstantState ,每次获取后,重新创建一个新的Drawable

Drawable 组件化

我们app 在探究组件化的过程中关于drawable 的问题也遇到了不少, 由于组件化开发的过程是先有的app,我们再对app进行组件化拆分,在组件化的初期,很多资源文件都是到处copy 的,虽然我们给组件添加了 resourcePrefix 这个属性,为每个组件的xml 资源命名做了限制,还是造成了不少打最终包成功后样式对不上的问题,而且随着项目越来越大,新写一个drawable 所耗费的时间,比找到一个相同属性的drawable 的xml文件还要快一点,这样就造成了恶性循环,大家就不停的创建新的drawable.xml 文件,找到相同属性的就更难了...

伴随着这样的思考,能不能找到一个摆脱xml来设置背景drawable 的方法就这样诞生了,但是这个过程也遇到了好几个问题

1.也就是上面我们所说的 drawable 缓存的问题,通过缓存 Drawable.ConstantState 每次获取都重新创建drawable 这个问题已经解决了
2.我在最开始的时候为整个项目重新定义了一套 DrawableView ,比如 DrawableTextView , DrawableLinearLayout , DrawableRelativeLayout 等等, 在为每个View 添加属性的时候,就产生了一个问题,那就是

<declare-styleable name="DrawableRelativeLayout">
      <attr name="rl_zhome_end_color" format="color"/>
      <attr name="rl_zhome_bottom_line" format="boolean"/>
  </declare-styleable>

<declare-styleable name="DrawableLinearLayout">
      <attr name="ll_zhome_end_color" format="color"/>
      <attr name="ll_zhome_bottom_line" format="boolean"/>
  </declare-styleable>

每一个View 在使用 xml 添加drawable 属性的时候,他们属性命名是不同的,LinearLayout 的属性就是 app:ll_zhome_color=""
RelativeLayout 的属性就是 app:rl_zhome_color="",这样就导致了不了解这个机制的人,如果只是copy属性,就会导致使用不了这个问题,那么能不能像 ConstraintLayout 一样, 所有view 的属性名都一致,并且android studio 还会自动提示出属性的名称呢,

这个问题的解决方案自己想一下其实也特别简单,那就是事先将属性声明出来,在自定义View 的 declare-styleable 引用这个属性就可以了,举个栗子

<resources>
先把这个 属性在 resources  标签下声明出来
<attr name="zhome_div_color" format="color"/>

<declare-styleable name="DrawableRelativeLayout">
      <attr name="zhome_div_color" />
  </declare-styleable>

<declare-styleable name="DrawableLinearLayout">
      <attr name="zhome_div_color" />
  </declare-styleable>
<resources>

这样就可以了,虽然在获取属性的时候是根据不同的View 来获取的,但是在编写 layout.xml 的过程中, 属性的命名是一致的,

      <com.tsm.tsmbottomsheetdialog.drawable.ZHomeLinearLayout
          android:layout_width="match_parent"
          android:layout_height="45dp"
          android:gravity="center_vertical"
          android:paddingHorizontal="16dp"
          android:orientation="horizontal"
          app:zhome_div_bottom_line="true"
          app:zhome_div_bottom_line_padding="16dp">

          <com.tsm.tsmbottomsheetdialog.drawable.ZHomeTextView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:textColor="@color/color_ct1_85"
              android:text="ZHomeLinearLayout  下划线"
              app:zhome_div_bottom_line="true"
              app:zhome_div_bottom_line_padding="16dp"/>

      </com.tsm.tsmbottomsheetdialog.drawable.ZHomeLinearLayout>
插个图 动画.gif

下面就是我们在使用过程中经常遇到的属性,我把它们每个属性都标注了出来,方便使用的人来查看并使用相关的属性,

<!--    选中方式   nor 没有   select->state_Selected      checked->state_Checked   enable->state_Enable   pressed->state_Pressed   -->
  <attr name="zhome_div_selector">
      <enum name="nor" value="0" />
      <enum name="select" value="1" />
      <enum name="checked" value="2" />
      <enum name="enable" value="3" />
      <enum name="pressed" value="4" />
  </attr>
  <!--   设置描边   描边宽度  虚线等属性选中与未选中状态公用 -->
  <!--    未选中   描边颜色-->
  <attr name="zhome_div_stroken_color" format="color"/>
  <!--    选中     描边颜色-->
  <attr name="zhome_div_select_state_stroken_color" format="color"/>
<!--    未选中与选中    描边宽度-->
  <attr name="zhome_div_stroken_width" format="dimension"/>
<!--    未选中与选中    间隔-->
  <attr name="zhome_div_stroken_dashgap" format="dimension"/>
<!--    未选中与选中    虚线宽度-->
  <attr name="zhome_div_stroken_dashwidth" format="dimension"/>
<!--    背景色-->
  <!--    未选中  颜色-->
  <attr name="zhome_div_color" format="color"/>
  <!--    选中   颜色-->
  <attr name="zhome_div_select_state_color" format="color"/>
  <!--    圆角  选中圆角与未选中圆角相同-->
  <attr name="zhome_div_radius" format="dimension"/>
<!--    左上圆角-->
  <attr name="zhome_div_top_left_radius" format="dimension"/>
<!--    右上圆角-->
  <attr name="zhome_div_top_right_radius" format="dimension"/>
<!--    左下圆角-->
  <attr name="zhome_div_bottom_left_radius" format="dimension"/>
<!--    右下圆角-->
  <attr name="zhome_div_bottom_right_radius" format="dimension"/>
<!--    顶部圆角  左上   右上-->
  <attr name="zhome_div_top_radius" format="dimension"/>
<!--    底部圆角  左下 右下-->
  <attr name="zhome_div_bottom_radius" format="dimension"/>
<!--    渐变色-->
<!--    渐变色角度-->
  <attr name="zhome_div_angle" format="integer"/>
<!--    渐变色开始颜色-->
  <attr name="zhome_div_start_color" format="color"/>
<!--    渐变色中间颜色-->
  <attr name="zhome_div_center_color" format="color"/>
<!--    渐变色结束颜色-->
  <attr name="zhome_div_end_color" format="color"/>
<!--    底部横线-->
  <attr name="zhome_div_bottom_line" format="boolean"/>
<!--   底部横线边距 部分UI 可能会出现底部横线距离两端存在一定间距-->
  <attr name="zhome_div_bottom_line_padding" format="dimension"/>

<!--    水波纹效果  由于有版本限制,这里使用前景色实现-->
  <attr name="zhome_div_ripple" format="boolean"/>
<!--    点击缩放效果-->
  <attr name="zhome_div_pressed_scale" format="boolean"/>

到了这里整个过程就告一段落了,这个一套drawable 在我们的组件里面已经试用了很长一段时间了,并没有出现什么问题,下面我方一下Github 地址 TsmBottomSheetDialog,这里就能找到相关代码

上一篇下一篇

猜你喜欢

热点阅读