解决使用skin-support换肤框架无法对NoticeView文字颜色和背景进行切换
Posted Steven Jon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解决使用skin-support换肤框架无法对NoticeView文字颜色和背景进行切换相关的知识,希望对你有一定的参考价值。
可是!没有那么多可是!
你当人干柴烈火,人家当你干炒牛河。
效果图:
如何解决?
使用NoticeView布局文件:
...
<com.jon.skindemo.NoticeView
android:id="@+id/nv_notices"
android:layout_width="400dp"
android:layout_height="wrap_content"
android:background="@drawable/input_bg"
android:layout_marginTop="40dp"
android:paddingStart="20dp"
android:paddingEnd="20dp"
app:nvTextColor="@color/textColor"
app:nvTextSize="28sp"
app:nvTextGravity="left"
app:nvInterval="4000"
app:nvTextMaxLines="2"/>
...
从上面可以看出,我们只需要改变background
和nvTextColor
这两项属性就可以实现根据当前肤色动态切换文字颜色和背景。
回到NoticeView的源码中:
nvTextColor
在哪个地方被使用的呢?
在TextFactory
内部类下的makeView()
方法下被使用的:
void resolve(TypedArray ta)
lines = ta.getInteger(R.styleable.NoticeView_nvTextMaxLines, lines);
size = ta.getDimension(R.styleable.NoticeView_nvTextSize, size);
color = ta.getColor(R.styleable.NoticeView_nvTextColor, color);
gravity = ta.getInteger(R.styleable.NoticeView_nvTextGravity, gravity);
@Override
public View makeView()
TextView tv = new TextView(getContext());
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
tv.setMaxLines(lines);
if (color != 1)
tv.setTextColor(color);
tv.setEllipsize(TextUtils.TruncateAt.END);
tv.setGravity(Gravity.CENTER_VERTICAL | gravity);
tv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
return tv;
那么makeView()
又被谁调用了呢?
被NoticeView
父类的父类ViewSwitcher
调用:
private View obtainView()
View child = mFactory.makeView();
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp == null)
lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
addView(child, lp);
return child;
而且还被调用两次:
/**
* Sets the factory used to create the two views between which the
* ViewSwitcher will flip. Instead of using a factory, you can call
* @link #addView(android.view.View, int, android.view.ViewGroup.LayoutParams)
* twice.
*
* @param factory the view factory used to generate the switcher's content
*/
public void setFactory(ViewFactory factory)
mFactory = factory;
obtainView();
obtainView();
因此,可以得出一个结论,makeView()
下的TextView会有两个,到时切换文字颜色时需操作两个TextView
:
//用List存放这两个TextView的引用
List<TextView> textViews = new ArrayList<>();
//在return tv之前添加引用
@Override
public View makeView()
TextView tv = new TextView(getContext());
....
textViews.add(tv);
return tv;
//切换文字颜色
if (mDefaultFactory.textViews.size() == 2)
mDefaultFactory.textViews.get(0).setTextColor(color);
mDefaultFactory.textViews.get(1).setTextColor(color);
到这里,NoticeView文字颜色就可以任意切换了,对于其背景切换就更简单了,Android-skin-support文档给出了一个示例Android-skin-support#自定义view换肤,可以参考这个示例代码,传送门SkinCompatAutoCompleteTextView
NoticeView修改全部代码
public class NoticeView extends TextSwitcher implements SkinCompatSupportable
private static final int[] TINT_ATTRS =
android.R.attr.background
;
private int mTextColorResId = INVALID_ID;
private int mBackgroundResId = INVALID_ID;
private Animation mInUp = anim(1.5f, 0);
private Animation mOutUp = anim(0, -1.5f);
private List<String> mDataList = new ArrayList<>();
private int mIndex = 0;
private int mInterval = 4000;
private int mDuration = 900;
private Drawable mIcon;
private int mIconTint = 0xff999999;
private int mIconPadding = 0;
private int mPaddingLeft = 0;
private boolean mIsVisible = false;
private boolean mIsStarted = false;
private boolean mIsResumed = true;
private boolean mIsRunning = false;
private final TextFactory mDefaultFactory = new TextFactory();
private final Runnable mRunnable = new Runnable()
@Override
public void run()
if (mIsRunning)
show(mIndex + 1);
postDelayed(mRunnable, mInterval);
;
public NoticeView(Context context)
this(context, null);
public NoticeView(Context context, AttributeSet attrs)
super(context, attrs);
initWithContext(context, attrs);
setInAnimation(mInUp);
setOutAnimation(mOutUp);
setFactory(mDefaultFactory);
mInUp.setDuration(mDuration);
mOutUp.setDuration(mDuration);
private void initWithContext(Context context, AttributeSet attrs)
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NoticeView);
mIcon = a.getDrawable(R.styleable.NoticeView_nvIcon);
mIconPadding = (int)a.getDimension(R.styleable.NoticeView_nvIconPadding, 0);
boolean hasIconTint = a.hasValue(R.styleable.NoticeView_nvIconTint);
if (hasIconTint)
mIconTint = a.getColor(R.styleable.NoticeView_nvIconTint, 0xff999999);
mInterval = a.getInteger(R.styleable.NoticeView_nvInterval, 4000);
mDuration = a.getInteger(R.styleable.NoticeView_nvDuration, 900);
mTextColorResId = a.getResourceId(R.styleable.NoticeView_nvTextColor, INVALID_ID);
mDefaultFactory.resolve(a);
a.recycle();
a = context.obtainStyledAttributes(attrs, TINT_ATTRS, 0, 0);
if (a.hasValue(0))
mBackgroundResId = a.getResourceId(0, INVALID_ID);
a.recycle();
if (mIcon != null)
mPaddingLeft = getPaddingLeft();
int realPaddingLeft = mPaddingLeft + mIconPadding + mIcon.getIntrinsicWidth();
setPadding(realPaddingLeft, getPaddingTop(), getPaddingRight(), getPaddingBottom());
if (hasIconTint)
mIcon = mIcon.mutate();
DrawableCompat.setTint(mIcon, mIconTint);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mIcon != null)
int y = (getMeasuredHeight() - mIcon.getIntrinsicWidth()) / 2;
mIcon.setBounds(mPaddingLeft, y, mPaddingLeft + mIcon.getIntrinsicWidth(), y + mIcon.getIntrinsicHeight());
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
if (mIcon != null)
mIcon.draw(canvas);
public int getIndex()
return mIndex;
public void start(List<String> list)
mDataList = list;
if (mDataList == null || mDataList.size() < 1)
mIsStarted = false;
update();
else
mIsStarted = true;
update();
show(0);
@Override
protected void onDetachedFromWindow()
super.onDetachedFromWindow();
mIsVisible = false;
update();
@Override
protected void onWindowVisibilityChanged(int visibility)
super.onWindowVisibilityChanged(visibility);
mIsVisible = visibility == VISIBLE;
update();
@Override
public boolean dispatchTouchEvent(MotionEvent ev)
int action = ev.getAction();
switch (action)
case MotionEvent.ACTION_DOWN:
mIsResumed = false;
update();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mIsResumed = true;
update();
break;
return super.dispatchTouchEvent(ev);
private void update()
boolean running = mIsVisible && mIsResumed && mIsStarted;
if (running != mIsRunning)
if (running)
postDelayed(mRunnable, mInterval);
else
removeCallbacks(mRunnable);
mIsRunning = running;
Log.e("ezy", "update() visible=" + mIsVisible + ", started=" + mIsStarted + ", running=" + mIsRunning);
private void show(int index)
mIndex = index % mDataList.size();
setText(html.fromHtml(mDataList.get(mIndex)));
private Animation anim(float from, float to)
final TranslateAnimation anim = new TranslateAnimation(0, 0f, 0, 0f, Animation.RELATIVE_TO_PARENT, from, Animation.RELATIVE_TO_PARENT, to);
anim.setDuration(mDuration);
anim.setFillAfter(false);
anim.setInterpolator(new LinearInterpolator());
return anim;
class TextFactory implements ViewFactory
DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
float size = dp2px(14);
int color = 1;
int lines = 1;
int gravity = Gravity.LEFT;
List<TextView> textViews = new ArrayList<>();
void resolve(TypedArray ta)
lines = ta.getInteger(R.styleable.NoticeView_nvTextMaxLines, lines);
size = ta.getDimension(R.styleable.NoticeView_nvTextSize, size);
color = ta.getColor(R.styleable.NoticeView_nvTextColor, color);
gravity = ta.getInteger(R.styleable.NoticeView_nvTextGravity, gravity);
private int dp2px(float dp)
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, dm);
@Override
public View makeView()
TextView tv = new TextView(getContext());
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
tv.setMaxLines(lines);
if (color != 1)
tv.setTextColor(color);
tv.setEllipsize(TextUtils.TruncateAt.END);
tv.setGravity(Gravity.CENTER_VERTICAL | gravity);
tv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
textViews.add(tv);
return tv;
@Override
public void applySkin()
mTextColorResId = SkinCompatHelper.checkResourceId(mTextColorResId);
if (mTextColorResId != INVALID_ID)
int color = SkinCompatResources.getColor(getContext(), mTextColorResId);
if (mDefaultFactory.textViews.size() == 2)
mDefaultFactory.textViews.get(0).setTextColor(color);
mDefaultFactory.textViews.get(1).setTextColor(color);
mBackgroundResId = SkinCompatHelper.checkResourceId(mBackgroundResId);
if (mBackgroundResId != INVALID_ID)
Drawable drawable = SkinCompatResources.getDrawableCompat(getContext(), mBackgroundResId);
setBackground(drawable);
非常感谢你能看到这里,如果能够帮助到你是我的荣幸!
以上是关于解决使用skin-support换肤框架无法对NoticeView文字颜色和背景进行切换的主要内容,如果未能解决你的问题,请参考以下文章
解决使用skin-support换肤框架无法对NoticeView文字颜色和背景进行切换