本文共 32085 字,大约阅读时间需要 106 分钟。
MagicaSakura 是 Android 多主题框架。
具有以下优点:首先进入Main的布局
对应Main怎么进入入口
//设置titleToolbar toolbar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(toolbar);getSupportActionBar().setTitle(null);//设置中间竖直可滑动部分RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler);LinearLayoutManager layoutManager = new LinearLayoutManager(this);layoutManager.setSmoothScrollbarEnabled(true);//进行分割线的操作recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { //8dp final int padding = getResources().getDimensionPixelOffset(R.dimen.padding_half); //返回适配器条目的位置 RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams(); final int position = layoutParams.getViewLayoutPosition(); if (position == 0) { outRect.left = outRect.top = outRect.right = padding; outRect.bottom = padding >> 1; } else if (position == state.getItemCount() - 1) { outRect.left = outRect.bottom = outRect.right = padding; outRect.top = padding >> 1; } else { outRect.left = outRect.right = padding; outRect.top = outRect.bottom = padding >> 1; } }});//设置进行水平还是垂直recyclerView.setLayoutManager(layoutManager);//设置适配器Adapter adapter = new Adapter();recyclerView.setAdapter(adapter);//适配器添加HolderTypeadapter.addViewHolderType( ViewHolder.VIEW_HOLDER_HEADER, ViewHolder.VIEW_HOLDER_LABEL, ViewHolder.VIEW_HOLDER_HEADER, ViewHolder.VIEW_HOLDER_LOGIN, ViewHolder.VIEW_HOLDER_HEADER, ViewHolder.VIEW_HOLDER_DOWNLOAD);
- 关于
Rect outRect
这个参数
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { }}
在这个参数中Rect outRect这个矩形控制条目的显示
- outRect.left : 控制条目距离左边的距离 - outRect.right:条目距离右边的距离 - outRect.top : 条目距离上边的距离 - outRect.bottom : 条目距离下边的距离
- 关于padding >> 1
相当于 padding/2的值
public static class Adapter extends RecyclerView.Adapter{ List viewHolderTypes = new ArrayList<>();//视图类型 SparseArrayCompat titleIndexs = new SparseArrayCompat<>();//标题集合 @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return ViewHolder.create(parent, viewType);根据类型创建每一个条目 } @Override public void onBindViewHolder(ViewHolder holder, int position) { //将数据绑定到item视图上 if (holder instanceof ViewHolderHeader) { ((ViewHolderHeader) holder).setTitle(titleIndexs.get(position)); } } //条目集合数 @Override public int getItemCount() { return viewHolderTypes.size(); } //根据位置得到type信息 @Override public int getItemViewType(int position) { return viewHolderTypes.get(position); } // public void addViewHolderType(int... type) { for (int i = 0; i < type.length; i++) { if (type[i] == ViewHolder.VIEW_HOLDER_HEADER) { titleIndexs.put(i, titleIndexs.size() + 1); } viewHolderTypes.add(type[i]); } notifyDataSetChanged(); }}
对于适配器,最次也要实现以下几个方法
//onCreateViewHolder()负责为Item创建视图@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return null;}//onBindViewHolder()负责将数据绑定到Item的视图上@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}//条目个数@Overridepublic int getItemCount() { return 0;}
根据type创建对应的ViewHolder
public static abstract class ViewHolder extends RecyclerView.ViewHolder { public static final int VIEW_HOLDER_HEADER = 0; public static final int VIEW_HOLDER_LABEL = VIEW_HOLDER_HEADER + 1; public static final int VIEW_HOLDER_LOGIN = VIEW_HOLDER_LABEL + 1; public static final int VIEW_HOLDER_DOWNLOAD = VIEW_HOLDER_LOGIN + 1; public ViewHolder(View itemView) { super(itemView); } public static ViewHolder create(ViewGroup viewHolder, int type) { switch (type) { case VIEW_HOLDER_HEADER: return ViewHolderHeader.create(viewHolder);//[1.1] case VIEW_HOLDER_LABEL: return ViewHolderLabel.create(viewHolder); case VIEW_HOLDER_LOGIN: return ViewHolderLogin.create(viewHolder); case VIEW_HOLDER_DOWNLOAD: return ViewHolderChoice.create(viewHolder); default: return null; } }}
1.1 通过上面的调用开始初始化布局
public static class ViewHolderHeader extends ViewHolder { private static final String[] sTitles = new String[]{ "Label", "Login", "Choice"}; TintImageView icon; TextView title; public ViewHolderHeader(View itemView) { super(itemView); icon = (TintImageView) itemView.findViewById(R.id.icon); title = (TextView) itemView.findViewById(R.id.title); } public void setTitle(int index) { title.setText(sTitles[index - 1]); icon.setImageResource(itemView.getResources().getIdentifier( "ic_looks_" + index, "drawable", itemView.getContext().getPackageName())); icon.setImageTintList(R.color.theme_color_primary); } //对每一种单独type的条目进行初始化 public static ViewHolderHeader create(ViewGroup parent) { return new ViewHolderHeader(LayoutInflater.from( parent.getContext()).inflate(R.layout.layout_list_item_header, parent, false)); }}
补充知识点
icon.setImageResource(itemView.getResources().getIdentifier("ic_looks_" + index, "drawable", itemView.getContext().getPackageName()));
其中getIdentifier得到的是resId,这个图片的名称是:ic_looks_xxx,其中第二个参数得到的是drawable,raw,id这些类型名称,第三个参数是包名
1
title.setCompoundDrawablesWithIntrinsicBounds(!isChecked ? R.drawable.selector_lock : R.drawable.selector_unlock, 0, 0, 0);
设置一个图标在此TextView的上下左右四个不同的位置
public class MyApplication extends Application implements ThemeUtils.switchColor { @Override public void onCreate() { super.onCreate(); //使用MyApplication中实现的接口 ThemeUtils.setSwitchColor(this); } //对应switchColor接口中的replaceColorById @Override public int replaceColorById(Context context, @ColorRes int colorId) { //判断是不是默认主题色 if (ThemeHelper.isDefaultTheme(context)) { return context.getResources().getColor(colorId); } //得到当前主题色 String theme = getTheme(context); if (theme != null) { colorId = getThemeColorId(context, colorId, theme); } return context.getResources().getColor(colorId); } //对应switchColor接口中的replaceColor,进行更换颜色 @Override public int replaceColor(Context context, @ColorInt int originColor) { //默认主题 if (ThemeHelper.isDefaultTheme(context)) { return originColor; } String theme = getTheme(context); int colorId = -1; if (theme != null) { colorId = getThemeColor(context, originColor, theme); } return colorId != -1 ? getResources().getColor(colorId) : originColor; } private String getTheme(Context context) { if (ThemeHelper.getTheme(context) == ThemeHelper.CARD_STORM) { return "blue"; } else if (ThemeHelper.getTheme(context) == ThemeHelper.CARD_HOPE) { return "purple"; } else if (ThemeHelper.getTheme(context) == ThemeHelper.CARD_WOOD) { return "green"; } else if (ThemeHelper.getTheme(context) == ThemeHelper.CARD_LIGHT) { return "green_light"; } else if (ThemeHelper.getTheme(context) == ThemeHelper.CARD_THUNDER) { return "yellow"; } else if (ThemeHelper.getTheme(context) == ThemeHelper.CARD_SAND) { return "orange"; } else if (ThemeHelper.getTheme(context) == ThemeHelper.CARD_FIREY) { return "red"; } return null; } //得到colorid private @ColorRes int getThemeColorId(Context context, int colorId, String theme) { switch (colorId) { case R.color.theme_color_primary: return context.getResources().getIdentifier(theme, "color", getPackageName()); case R.color.theme_color_primary_dark: return context.getResources().getIdentifier(theme + "_dark", "color", getPackageName()); case R.color.theme_color_primary_trans: return context.getResources().getIdentifier(theme + "_trans", "color", getPackageName()); } return colorId; } private @ColorRes int getThemeColor(Context context, int color, String theme) { switch (color) { case 0xfffb7299: return context.getResources().getIdentifier(theme, "color", getPackageName()); case 0xffb85671: return context.getResources().getIdentifier(theme + "_dark", "color", getPackageName()); case 0x99f0486c: return context.getResources().getIdentifier(theme + "_trans", "color", getPackageName()); } return -1; }}
//这个方法是TitleBar的方法,弹出一个Dialog@Overridepublic boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.change_theme) { CardPickerDialog dialog = new CardPickerDialog(); dialog.setClickListener(this); dialog.show(getSupportFragmentManager(), CardPickerDialog.TAG); return true; } return super.onOptionsItemSelected(item);}
自定义Dialog CardPickerDialog
比如当前设置pink主题
case R.id.theme_pink: mCurrentTheme = ThemeHelper.CARD_SAKURA; setImageButtons(mCurrentTheme); break;
当点击确定时
if (mClickListener != null) { mClickListener.onConfirm(mCurrentTheme);}
@Overridepublic void onConfirm(int currentTheme) { if (ThemeHelper.getTheme(MainActivity.this) != currentTheme) { //当不是当前主题时进行设置,写入sp内 ThemeHelper.setTheme(MainActivity.this, currentTheme); // ThemeUtils.refreshUI(MainActivity.this, new ThemeUtils.ExtraRefreshable() { @Override public void refreshGlobal(Activity activity) { //for global setting, just do once if (Build.VERSION.SDK_INT >= 21) { //设置全局的标题栏 final MainActivity context = MainActivity.this; ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription(null, null, ThemeUtils.getThemeAttrColor(context, android.R.attr.colorPrimary)); setTaskDescription(taskDescription); //设置状态栏颜色 getWindow().setStatusBarColor( ThemeUtils.getColorById(context, R.color.theme_color_primary_dark)); } } @Override public void refreshSpecificView(View view) { } } ); //底部显示一个黑框信息 View view = findViewById(R.id.snack_layout); if (view != null) { TextView textView = (TextView) view.findViewById(R.id.content); textView.setText(getSnackContent(currentTheme)); SnackAnimationUtil.with(this, R.anim.snack_in, R.anim.snack_out) .setDismissDelayTime(1000) .setTarget(view) .play(); } }}
//得到系统定义的contentviewView rootView = activity.getWindow().getDecorView().findViewById(android.R.id.content);refreshView(rootView, extraRefreshable);
private static void refreshView(View view, ExtraRefreshable extraRefreshable) { if (view == null) return; view.destroyDrawingCache(); //如果View继承了Tintable,则利用tint方法去处理,我们稍后看这个方法如何处理 if (view instanceof Tintable) { ((Tintable) view).tint(); //当处理后递归遍历该view容器下的其他控件 if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { refreshView(((ViewGroup) view).getChildAt(i), extraRefreshable); } } } else { // if (extraRefreshable != null) { extraRefreshable.refreshSpecificView(view); } if (view instanceof AbsListView) { try { //final RecycleBin mRecycler = new RecycleBin();对应拿到这个引用 if (sRecyclerBin == null) { sRecyclerBin = AbsListView.class.getDeclaredField("mRecycler"); sRecyclerBin.setAccessible(true); } if (sListViewClearMethod == null) { //拿到RecycleBin中的clear方法 sListViewClearMethod = Class.forName("android.widget.AbsListView$RecycleBin") .getDeclaredMethod("clear"); sListViewClearMethod.setAccessible(true); } //执行clear方法进行所有缓存view的清除 sListViewClearMethod.invoke(sRecyclerBin.get(view)); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } //更新每一个视图 ListAdapter adapter = ((AbsListView) view).getAdapter(); while (adapter instanceof WrapperListAdapter) { adapter = ((WrapperListAdapter) adapter).getWrappedAdapter(); } if (adapter instanceof BaseAdapter) { ((BaseAdapter) adapter).notifyDataSetChanged(); } } if (view instanceof RecyclerView) { try { if (sRecycler == null) { sRecycler = RecyclerView.class.getDeclaredField("mRecycler"); sRecycler.setAccessible(true); } if (sRecycleViewClearMethod == null) { sRecycleViewClearMethod = Class.forName("android.support.v7.widget.RecyclerView$Recycler") .getDeclaredMethod("clear"); sRecycleViewClearMethod.setAccessible(true); } sRecycleViewClearMethod.invoke(sRecycler.get(view)); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } ((RecyclerView) view).getRecycledViewPool().clear(); ((RecyclerView) view).invalidateItemDecorations(); } if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { refreshView(((ViewGroup) view).getChildAt(i), extraRefreshable); } } } }
这样相当于核心又落到了Tintable.tint()方法
我们就先拿TintView说起
public class TintView extends View implements Tintable, AppCompatBackgroundHelper.BackgroundExtensible { private AppCompatBackgroundHelper mBackgroundHelper; public TintView(Context context) { this(context, null); } public TintView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public TintView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //编辑模式就退出 if (isInEditMode()) { return; } //此时理解成操作类 TintManager tintManager = TintManager.get(context);//[3.1] //利用AppCompatBackgroundHelper组合当前控件和操作类TintManager mBackgroundHelper = new AppCompatBackgroundHelper(this, tintManager);//[3.2] mBackgroundHelper.loadFromAttribute(attrs, defStyleAttr);//[3.3] } ...}
现在我们就开始通过构造入口了解
3.1 TintManager.get(context)
目的很简单就是根据context生成对应的TintManager,然后添加到名称是INSTANCE_CACHE的WeakHashMap弱引用Map中
private static final WeakHashMapINSTANCE_CACHE = new WeakHashMap<>();public static com.bilibili.magicasakura.utils.TintManager get(Context context) { if (context == null) return null; if (context instanceof ContextThemeWrapper) { context = ((ContextThemeWrapper) context).getBaseContext(); } if (context instanceof android.view.ContextThemeWrapper) { context = ((android.view.ContextThemeWrapper) context).getBaseContext(); } com.bilibili.magicasakura.utils.TintManager tm = INSTANCE_CACHE.get(context); if (tm == null) { tm = new com.bilibili.magicasakura.utils.TintManager(context);//3.1.1 INSTANCE_CACHE.put(context, tm); } return tm;}
3.1.1 TintManager构造
private TintManager(Context context) { mContextRef = new WeakReference<>(context);}
3.2 new AppCompatBackgroundHelper(this, tintManager)
就是一个存入的功能
public AppCompatBaseHelper(T view, TintManager tintManager) { mView = view; mTintManager = tintManager;}public AppCompatBackgroundHelper(View view, TintManager tintManager) { super(view, tintManager);}
3.3 AppCompatBackgroundHelper.loadFromAttribute()
@SuppressWarnings("ResourceType")@Overridevoid loadFromAttribute(AttributeSet attrs, int defStyleAttr) { initPadding();//得到view的上下左右padding //得到早定义的属性 TypedArray array = mView.getContext().obtainStyledAttributes(attrs, R.styleable.TintViewBackgroundHelper, defStyleAttr, 0); //如果backgroundTint这个参数有值 if (array.hasValue(R.styleable.TintViewBackgroundHelper_backgroundTint)) { //设置值 mBackgroundTintResId = array.getResourceId(R.styleable.TintViewBackgroundHelper_backgroundTint, 0); //之后看backgroundTintMode设置的模式是什么 if (array.hasValue(R.styleable.TintViewBackgroundHelper_backgroundTintMode)) { //先进行解析模式,然后进行设置 //这里进行[3.3.1],[3.3.2]处理 setSupportBackgroundTintMode(DrawableUtils.parseTintMode(array.getInt(R.styleable.TintViewBackgroundHelper_backgroundTintMode, 0), null)); } setSupportBackgroundTint(mBackgroundTintResId);//[3.3.3] } else { //如果没有设置backgroundTint,那就看android_background设置的值,如果设置了就设置背景了 Drawable drawable = mTintManager.getDrawable(mBackgroundResId = array.getResourceId(R.styleable.TintViewBackgroundHelper_android_background, 0)); if (drawable != null) { setBackgroundDrawable(drawable); } } array.recycle();}
3.3.1
DrawableUtils.parseTintMode(array.getInt(R.styleable.TintViewBackgroundHelper_backgroundTintMode, 0), null)
返回对应的mode
public static PorterDuff.Mode parseTintMode(int value, PorterDuff.Mode defaultMode) { switch (value) { case 3: return PorterDuff.Mode.SRC_OVER; case 5: return PorterDuff.Mode.SRC_IN; case 9: return PorterDuff.Mode.SRC_ATOP; case 14: return PorterDuff.Mode.MULTIPLY; case 15: return PorterDuff.Mode.SCREEN; case 16: return Build.VERSION.SDK_INT >= 11 ? PorterDuff.Mode.valueOf("ADD") : defaultMode; default: return defaultMode; }}
3.3.2
当mode不等于null的时候用一个TintInfo记录,我们需要记住mHasTintMode,mTintMode已经有值此时
private void setSupportBackgroundTintMode(PorterDuff.Mode mode) { if (mBackgroundTintResId != 0 && mode != null) { if (mBackgroundTintInfo == null) { mBackgroundTintInfo = new TintInfo(); } mBackgroundTintInfo.mHasTintMode = true; mBackgroundTintInfo.mTintMode = mode; }}
3.3.3 setSupportBackgroundTint()
当设置backgroundTint的时候得到mBackgroundTintResId进行操作
private boolean setSupportBackgroundTint(int resId) { if (resId != 0) { if (mBackgroundTintInfo == null) { mBackgroundTintInfo = new TintInfo(); } mBackgroundTintInfo.mHasTintList = true; mBackgroundTintInfo.mTintList = mTintManager.getColorStateList(resId); } return applySupportBackgroundTint();//[3.3.4]}
applySupportBackgroundTint()
private boolean applySupportBackgroundTint() { Drawable backgroundDrawable = mView.getBackground(); if (backgroundDrawable != null && mBackgroundTintInfo != null && mBackgroundTintInfo.mHasTintList) { backgroundDrawable = DrawableCompat.wrap(backgroundDrawable); backgroundDrawable = backgroundDrawable.mutate();//起到单一修改背景的作用,并不会影响其他控件的色 if (mBackgroundTintInfo.mHasTintList) { //对背景设置颜色 DrawableCompat.setTintList(backgroundDrawable, mBackgroundTintInfo.mTintList); } if (mBackgroundTintInfo.mHasTintMode) { //还可以根据view不同的状态进行着色 DrawableCompat.setTintMode(backgroundDrawable, mBackgroundTintInfo.mTintMode); } //看是否backgroundDrawable进行改变 if (backgroundDrawable.isStateful()) { backgroundDrawable.setState(mView.getDrawableState()); } setBackgroundDrawable(backgroundDrawable); return true; } return false;}
这里参考一片文章:
我们通过项目再来举个栗子
public static class ViewHolderHeader extends ViewHolder { public static ViewHolderHeader create(ViewGroup parent) { return new ViewHolderHeader(LayoutInflater.from( parent.getContext()).inflate(R.layout.layout_list_item_header, parent, false)); }}
以原图完全显示为目的,将图片的内容完整居中显示,通过按比例缩小原图的size宽(高)等于或小于ImageView的宽(高)
对应:imageTint<color name="theme_color_primary">#fb7299</color>
public class TintImageView extends ImageView implements Tintable, AppCompatBackgroundHelper.BackgroundExtensible, AppCompatImageHelper.ImageExtensible { public TintImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); if (isInEditMode()) { return; } //生成TintManager TintManager tintManager = TintManager.get(context); //记录当前View与TintManager mBackgroundHelper = new AppCompatBackgroundHelper(this, tintManager);//[4.1] mBackgroundHelper.loadFromAttribute(attrs, defStyleAttr);//[4.2] mImageHelper = new AppCompatImageHelper(this, tintManager);//[4.3] mImageHelper.loadFromAttribute(attrs, defStyleAttr);//[4.4] } ... }
其中4.1和4.3都是记录作用就不多说
4.2 AppCompatBackgroundHelper.loadFromAttribute()
这里支持通过backgroundTintMode设置mode
void loadFromAttribute(AttributeSet attrs, int defStyleAttr) { initPadding();//获取padding TypedArray array = mView.getContext().obtainStyledAttributes(attrs, R.styleable.TintViewBackgroundHelper, defStyleAttr, 0); if (array.hasValue(R.styleable.TintViewBackgroundHelper_backgroundTint)) { //得到backgroundTint属性的值 mBackgroundTintResId = array.getResourceId(R.styleable.TintViewBackgroundHelper_backgroundTint, 0); if (array.hasValue(R.styleable.TintViewBackgroundHelper_backgroundTintMode)) { //得到backgroundTintMode的值并set,然后通过setSupportBackgroundTintMode设置进去 setSupportBackgroundTintMode(DrawableUtils.parseTintMode(array.getInt(R.styleable.TintViewBackgroundHelper_backgroundTintMode, 0), null)); } setSupportBackgroundTint(mBackgroundTintResId); } else { Drawable drawable = mTintManager.getDrawable(mBackgroundResId = array.getResourceId(R.styleable.TintViewBackgroundHelper_android_background, 0)); if (drawable != null) { setBackgroundDrawable(drawable); } } array.recycle();}
首先用TintInfo记录,
private boolean setSupportBackgroundTint(int resId) { if (resId != 0) { if (mBackgroundTintInfo == null) { mBackgroundTintInfo = new TintInfo(); } mBackgroundTintInfo.mHasTintList = true; mBackgroundTintInfo.mTintList = mTintManager.getColorStateList(resId);//是上一步配置的backgroundTint } return applySupportBackgroundTint();//[4.2.1]}
4.2.1 applySupportBackgroundTint()
private boolean applySupportBackgroundTint() { Drawable backgroundDrawable = mView.getBackground(); if (backgroundDrawable != null && mBackgroundTintInfo != null && mBackgroundTintInfo.mHasTintList) { //包装以后可进行着色 backgroundDrawable = DrawableCompat.wrap(backgroundDrawable); backgroundDrawable = backgroundDrawable.mutate();//起到单一修改背景的作用,并不会影响其他控件的色 if (mBackgroundTintInfo.mHasTintList) { //对背景设置颜色 DrawableCompat.setTintList(backgroundDrawable, mBackgroundTintInfo.mTintList); } if (mBackgroundTintInfo.mHasTintMode) { //还可以根据view不同的状态进行着色 DrawableCompat.setTintMode(backgroundDrawable, mBackgroundTintInfo.mTintMode); } if (backgroundDrawable.isStateful()) { backgroundDrawable.setState(mView.getDrawableState()); } setBackgroundDrawable(backgroundDrawable); return true; } return false;}
此时背景色已经设置完成
我们再来回顾一下,到底从哪里开始执行变色
private static void refreshView(View view, ExtraRefreshable extraRefreshable) { if (view == null) return; view.destroyDrawingCache(); if (view instanceof Tintable) { ((Tintable) view).tint();//看这里
这个方法我们可以查看上面的回顾
TintImageView
@Overridepublic void tint() { if (mBackgroundHelper != null) { mBackgroundHelper.tint();//看一个就好 } if (mImageHelper != null) { mImageHelper.tint(); }}
@Overridepublic void tint() { if (mBackgroundTintResId == 0 || !setSupportBackgroundTint(mBackgroundTintResId)) { Drawable drawable = mTintManager.getDrawable(mBackgroundResId);//思想是根据mBackgroundResId得到Drawable if (drawable == null) { drawable = mBackgroundResId == 0 ? null : ContextCompat.getDrawable(mView.getContext(), mBackgroundResId); } setBackgroundDrawable(drawable);//设置背景 }}
最后我们就明白如何更换主题,我们主要是利用自定义控件,然后通过统一的设置进行更改。
FilterableStateListDrawable
ColorStateListUtilsDrawableInflateDelegateDrawableUtilsGradientDrawableInflateImplInputConnectionImplLayerDrawableInflateImplRippleDrawableInflateImplStateListDrawableInflateImplThemeUtilsTintInfoTintManagerVectorDrawableInflateImpl
AppCompatBackgroundHelperAppCompatBaseHelperAppCompatCompoundButtonHelperAppCompatCompoundDrawableHelperAppCompatForegroundHelperAppCompatImageHelperAppCompatProgressBarHelperAppCompatSwitchHelperAppCompatTextHelperTintableTintAppAlertDialogDividingViewTintAppBarLayoutTintAutoCompleteTextViewTintButtonTintCheckBoxTintCheckedTextViewTintConstraintLayoutTintEditTextTintFrameLayoutTintGridLayoutTintImageViewTintLinearLayoutTintProgressBarTintProgressDialogTintRadioButtonTintRelativeLayoutTintSwitchCompatTintTextViewTintToolbarTintView
FilterableStateListDrawable
这个类是针对StateListDrawable不能针对单一的状态添加colorFilter设计的
public class FilterableStateListDrawable extends StateListDrawable { private int currIdx = -1; private int childrenCount = 0; private SparseArrayfilterMap; public FilterableStateListDrawable() { super(); filterMap = new SparseArray<>(); } @Override public void addState(int[] stateSet, Drawable drawable) { super.addState(stateSet, drawable); childrenCount++; } public void addState(int[] stateSet, Drawable drawable, ColorFilter colorFilter) { if (colorFilter == null) { addState(stateSet, drawable); return; } // this is a new custom method, does not exist in parent class int currChild = childrenCount; addState(stateSet, drawable); filterMap.put(currChild, colorFilter); } @Override public boolean selectDrawable(int idx) { boolean result = super.selectDrawable(idx); // check if the drawable has been actually changed to the one I expect if (getCurrent() != null) { currIdx = result ? idx : currIdx; setColorFilter(getColorFilterForIdx(currIdx)); } else { currIdx = -1; setColorFilter(null); } return result; } private ColorFilter getColorFilterForIdx(int idx) { return filterMap != null ? filterMap.get(idx) : null; } @Override public ConstantState getConstantState() { return super.getConstantState(); }}
根据一个SparseArray这样就对应每一种状态有一个ColorFilter了。
ColorFilter主要用来处理颜色
- ColorMatrixColorFilter - LightingColorFilter - PorterDuffColorFilter反正都是对图片颜色进行处理
再来看看ColorStateList的作用
/** * 对TextView设置ColorStateList使其在Normal、Pressed、Focused、Unable四种状态下显示不同的颜色。 * StateListDrawable可直接使用图片应用在相似场合。 */ public class ActColorStateList extends Activity implements OnClickListener { private TextView txtShow; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); txtShow = (TextView) findViewById(R.id.txtShow); txtShow.setText("Sodino\nNormal:0xffffffff\nPressed:0xffffff00\nFocused:0xff0000ff\nUnable:0xffff0000"); txtShow.setTextColor(createColorStateList(0xffffffff, 0xffffff00, 0xff0000ff, 0xffff0000)); txtShow.setOnClickListener(this); } /** 对TextView设置不同状态时其文字颜色。 */ private ColorStateList createColorStateList(int normal, int pressed, int focused, int unable) { int[] colors = new int[] { pressed, focused, normal, focused, unable, normal }; int[][] states = new int[6][]; states[0] = new int[] { android.R.attr.state_pressed, android.R.attr.state_enabled }; states[1] = new int[] { android.R.attr.state_enabled, android.R.attr.state_focused }; states[2] = new int[] { android.R.attr.state_enabled }; states[3] = new int[] { android.R.attr.state_focused }; states[4] = new int[] { android.R.attr.state_window_focused }; states[5] = new int[] {}; ColorStateList colorList = new ColorStateList(states, colors); return colorList; } /** 设置Selector。 */ public static StateListDrawable newSelector(Context context, int idNormal, int idPressed, int idFocused, int idUnable) { StateListDrawable bg = new StateListDrawable(); Drawable normal = idNormal == -1 ? null : context.getResources().getDrawable(idNormal); Drawable pressed = idPressed == -1 ? null : context.getResources().getDrawable(idPressed); Drawable focused = idFocused == -1 ? null : context.getResources().getDrawable(idFocused); Drawable unable = idUnable == -1 ? null : context.getResources().getDrawable(idUnable); // View.PRESSED_ENABLED_STATE_SET bg.addState(new int[] { android.R.attr.state_pressed, android.R.attr.state_enabled }, pressed); // View.ENABLED_FOCUSED_STATE_SET bg.addState(new int[] { android.R.attr.state_enabled, android.R.attr.state_focused }, focused); // View.ENABLED_STATE_SET bg.addState(new int[] { android.R.attr.state_enabled }, normal); // View.FOCUSED_STATE_SET bg.addState(new int[] { android.R.attr.state_focused }, focused); // View.WINDOW_FOCUSED_STATE_SET bg.addState(new int[] { android.R.attr.state_window_focused }, unable); // View.EMPTY_STATE_SET bg.addState(new int[] {}, normal); return bg; } @Override public void onClick(View v) { if (v == txtShow) { txtShow.setEnabled(false); } } }
具体使用方法请
欢迎关注公众号:码老板