Android动态替换图标总结

现在淘宝,京东等App在节假日打开时,都是采用一套节假日的图标,这种不用发版本,又可以随着后台配置动态替换图标固然是很方便,体验很好的事情.

准备工作:全部按钮的不同状态改为纯图片实现.

现在很多应用的通知策略都是采用小红点提示,小红点可以单独画出来,与图标分离,单独控制隐藏.但是现在需要动态替换图标,小红点就不能与图片分离了,否则会导致红点位置不理想或红点被图标遮住等问题.为此,所有的状态都需要改为纯图片实现.

首页的tab,目前应用采用的是RadioButton + Fragment的实现,为此,需要自定义RadioButton的selector.

  1. 定义attr.

     //下面定义的state_new_message表示有新消息
     <declare-styleable name="MessageRadioButton">
         <attr name="state_new_message" format="boolean"/>
     </declare-styleable>
  2. 定义selector.

     //xxx为你的包名
     //为了配合state_checked,需要4张图片
     <?xml version="1.0" encoding="utf-8"?>
     <selector xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:message="http://schemas.android.com/apk/res/xxx">
         <item android:drawable="@drawable/icon_union_selected"
             android:state_checked="true"
             message:state_new_message="false"/>
         <item android:drawable="@drawable/icon_union_selected_new"
             android:state_checked="true"
             message:state_new_message="true"/>
         <item android:drawable="@drawable/icon_union_normal" 
             android:state_checked="false"
             message:state_new_message="false"/>
         <item android:drawable="@drawable/icon_union_normal_new" 
             android:state_checked="false"
             message:state_new_message="true"/>
     </selector>
  3. 重写RadioButton(ImageView等控件也同样适用).

     public class MessageRadioButton extends RadioButton {
         //定义的状态
         private static final int[] STATE_NEW_MESSAGE = {R.attr.state_new_message};
         //是否有新消息
         private boolean hasNewMessage;
    
         /**
          * 构造函数
          **/
    
         /**
          * 关键需要此函数,添加状态
          **/
         @Override
         protected int[] onCreateDrawableState(int extraSpace) {
             if (hasNewMessage) {
                 final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
                 mergeDrawableStates(drawableState, STATE_NEW_MESSAGE);
                 return drawableState;
             }
             return super.onCreateDrawableState(extraSpace);
         }
    
         /**
          * 设置是否有新消息数
          * @param newMessage, 是否有新消息数
          */
         public void setHasNewMessage(boolean newMessage) {
             if (hasNewMessage != newMessage) {
                 hasNewMessage = newMessage;
                 refreshDrawableState();
             }
         }
    
     }

使用MessageRadioButton的setHasNewMessage()方法即可以显示带小红点的图片.
所有按钮改为图片实现.

创建Drawable对象

动态配置就是下载图片成功后,从文件中获取每个按钮的Drawable对象.但是实现时需要注意细节:

  1. 根据图片生成的Drawable对象即BitmapDrawable.

    • 目前BitmapDrawable对应的构造函数未被弃用的还有

        BitmapDrawable(Resources res, Bitmap bitmap)
        BitmapDrawable(Resources res, String path)

      但使用BitmapDrawable(Resources res, String path)时发现在vivo手机上没有生效,所以还是推荐BitmapDrawable(Resources res, Bitmap bitmap)方法.

    • 图片在使用时也需要区分dpi,对应Bitmap.setDensity()方法,参数为160的倍数.

  2. selector对应的Drawable对象即StateListDrawable.

    • StateListDrawable.addState(int[] stateSet, Drawable drawable)方法可以添加状态对应的drawable.

        //state_new_message为false
        listDrawable.addState(new int[]{-R.attr.state_new_message}, drawable);
        //state_new_message为true
        listDrawable.addState(new int[]{R.attr.state_new_message}, drawable);
    • listDrawable必须调用setBounds()方法才能显示.