Android字体渐变效果,这一篇就够了!
BATcoder技术群,让一部分人先进大厂
大家好,我是刘望舒,腾讯TVP,著有三本业内知名畅销书,连续四年蝉联电子工业出版社年度优秀作者,百度百科收录的高级技术专家。
前华为架构师,现大厂技术总监。
想要加入 BATcoder技术群,公号回复BAT
即可。
https://blog.csdn.net/weixin_44819566
public class GradualChangeTv extends AppCompatTextView {
public Paint mPaint = new Paint();
public final String text = "android 超级兵";
public GradualChangeTv(Context context) {
this(context, null);
}
public GradualChangeTv(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public GradualChangeTv(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint.setColor(Color.RED);
//抗锯齿
mPaint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/*
* 绘制文字
* 参数一: 绘制文字
* 参数二: x轴开始位置
* 参数三: y 轴开始位置
* 参数四: 画笔
*/
canvas.drawText(text, 0, 0, mPaint);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//获取当前控件的宽高
int viewWidth = getWidth() / 2;
int viewHeight = getHeight() / 2;
/*
* 绘制文字
* 参数一: 绘制文字
* 参数二: x轴开始位置
* 参数三: y 轴开始位置
* 参数四: 画笔
*/
canvas.drawText(text, viewWidth, viewHeight, mPaint);
//绘制居中线
drawCenterLine(canvas, viewWidth, viewHeight);
}
private void drawCenterLine(Canvas canvas, int viewWidth, int viewHeight) {
//垂直线
canvas.drawLine(viewWidth, 0, viewWidth, getHeight(), mPaint);
//水平线
canvas.drawLine(0,viewHeight,getWidth(),viewHeight,mPaint);
}
通过mPaint.measureText(text) 获取文字宽 通过mPaint.descent() + mPaint.ascent(); 获取文字高 然后控件各取一半,让控件减去即可
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//文字宽度
float textWidth = mPaint.measureText(text);
//文字高度
float textHeight = mPaint.descent() + mPaint.ascent();
//获取当前控件的宽高
int viewWidth = getWidth() / 2;
int viewHeight = getHeight() / 2;
canvas.drawText(text, viewWidth - textWidth / 2, viewHeight - textHeight / 2, mPaint);
//绘制居中线
drawCenterLine(canvas, viewWidth, viewHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//文字宽度
float textWidth = mPaint.measureText(text);
//文字高度
float textHeight = mPaint.descent() + mPaint.ascent();
//获取当前控件的宽高的一半
int viewWidth = getWidth() / 2;
int viewHeight = getHeight() / 2;
//裁剪
drawClip(canvas, viewWidth, viewHeight, textWidth, textHeight);
//绘制居中线
drawCenterLine(canvas, viewWidth, viewHeight);
}
private void drawClip(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
mPaint.setColor(Color.BLACK);
canvas.save();
//绘制文字X轴的位置
float left = viewWidth - textWidth / 2;
//绘制文字Y轴的位置
float right = viewHeight - textHeight / 2;
//裁剪
canvas.clipRect((int) left, 0, (int) left + 300, getHeight());
/*
* 绘制文字
* 参数一: 绘制文字
* 参数二: x轴开始位置
* 参数三: y 轴开始位置
* 参数四: 画笔
*/
canvas.drawText(text, left, right, mPaint);
canvas.restore();
}
参数一: 从文字开始位置绘制 参数二: 顶部裁剪为0 参数三: 裁剪宽度 参数四: 绘制高度
绘制两层(两层颜色不同),两层叠加起来 然后通过裁剪将上面一层给裁剪掉
//用来记录当前进度 【0-1】
float progress = 0.3f;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//文字宽度
float textWidth = mPaint.measureText(text);
//文字高度
float textHeight = mPaint.descent() + mPaint.ascent();
//获取当前控件的宽高的一半
int viewWidth = getWidth() / 2;
int viewHeight = getHeight() / 2;
//绘制底层
drawBottom(canvas, viewWidth, viewHeight, textWidth, textHeight);
//绘制上层【颜色渐变的】
drawUp(canvas, viewWidth, viewHeight, textWidth, textHeight);
//绘制居中线
drawCenterLine(canvas, viewWidth, viewHeight);
}
//绘制上层【渐变的】
private void drawUp(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
mPaint.setColor(Color.BLACK);
canvas.save();
//绘制文字X轴的位置
float left = viewWidth - textWidth / 2;
//绘制文字Y轴的位置
float right = viewHeight - textHeight / 2;
//裁剪
canvas.clipRect((int) left, 0, (int) left + textWidth * progress, getHeight());
/*
* 绘制文字
* 参数一: 绘制文字
* 参数二: x轴开始位置
* 参数三: y 轴开始位置
* 参数四: 画笔
*/
canvas.drawText(text, left, right, mPaint);
canvas.restore();
}
//绘制下层 不动的
private void drawBottom(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
mPaint.setColor(Color.RED); //文字颜色
canvas.save();
//文字开始位置
float left = viewWidth - textWidth / 2;
/*
* 绘制文字
* 参数一: 绘制文字
* 参数二: x轴开始位置
* 参数三: y 轴开始位置
* 参数四: 画笔
*/
canvas.drawText(text, left, viewHeight - textHeight / 2, mPaint);
canvas.restore();
}
//裁剪
canvas.clipRect((int) left, 0, (int) left + textWidth * progress, getHeight());
textWidth需要绘制文字的宽度 viewWidth控件宽度的一半 文字开始的位置:left = viewWidth - textWidth / 2 文字需要裁剪的位置:文字的宽度 * progress
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
progress = event.getX() / getWidth();
invalidate();
}
return true;
}
private void drawRightToLeft(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
mPaint.setColor(Color.GREEN);
/*
* 这里 left和right能够在此抽取出来,不过这样写很易懂,有需求自己弄吧!!!
*/
canvas.save();
//绘制文字X轴的位置 【文字开始的位置】
float textX = viewWidth - textWidth / 2;
//绘制文字Y轴的位置
float textY = viewHeight - textHeight / 2;
//文字结束的位置
float end = viewWidth + mPaint.measureText(text) / 2;
canvas.clipRect(end, 0, textX + textWidth * (1 - progress), getHeight());
canvas.drawText(text, textX, textY, mPaint);
canvas.restore();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (type == GradualChangeTextView.GRADUAL_CHANGE_RIGHT) {
//从右到左滑动
progress = 1 - event.getX() / getWidth();
} else if (type == GradualChangeTextView.GRADUAL_CHANGE_LEFT) {
//从左到右滑动
progress = event.getX() / getWidth();
}
invalidate();
}
return true;
}
//text1 .. text4 是控件id
val textList = listOf(text1, text2, text3, text4)
val list = listOf(HomeFragment(), MyFragment(), TestFragment(), SettingFragment())
val viewPagerAdapter = ViewPagerAdapter(supportFragmentManager, list)
viewPager.adapter = viewPagerAdapter
//默认选择第一页
viewPager.currentItem = 1
//默认选中
textList[viewPager.currentItem].percent = 1f
viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int,
) {
if (positionOffset > 0) {
val left = textList[position]
val right = textList[position + 1]
//从右到左滑动
left.setSlidingPosition(GradualChangeTextView.GRADUAL_CHANGE_RIGHT)
//从左到右滑动
right.setSlidingPosition(GradualChangeTextView.GRADUAL_CHANGE_LEFT)
//当前页面取反[从右到左]
left.percent = 1 - positionOffset
//下一个页面正常[从左到右]
right.percent = positionOffset
}
}
override fun onPageSelected(position: Int) { }
override fun onPageScrollStateChanged(state: Int) {
//当 ViewPage结束的时候,重新设置一下状态 [不设置的话滑动太快,会导致'残影']
textList.forEach {
if (it.tag == textList[viewPager.currentItem].tag) {
it.percent = 1f
} else {
it.percent = 0f
}
}
}
})
https://www.jianshu.com/p/2cc6d5842986
原色 – 没有被过度绘制 – 这部分的像素点只在屏幕上绘制了一次。 蓝色 – 1次过度绘制– 这部分的像素点只在屏幕上绘制了两次。 绿色 – 2次过度绘制 – 这部分的像素点只在屏幕上绘制了三次。 粉色 – 3次过度绘制 – 这部分的像素点只在屏幕上绘制了四次。 红色 – 4次过度绘制 – 这部分的像素点只在屏幕上绘制了五次。
//绘制下层 不动的
private void drawBottom(Canvas canvas, int viewWidth, int viewHeight, float textWidth, float textHeight) {
mPaint.setColor(Color.RED);
canvas.save();
//绘制文字X轴的位置 [文字开始的位置]
float textX = viewWidth - textWidth / 2;
//绘制文字Y轴的位置
float textY = viewHeight - textHeight / 2;
//跟随者上层裁剪
canvas.clipRect((int) textX + textWidth * progress, 0, textWidth + viewWidth, getHeight());
/*
* 绘制文字
* 参数一: 绘制文字
* 参数二: x轴开始位置
* 参数三: y 轴开始位置
* 参数四: 画笔
*/
canvas.drawText(text, textX, textY, mPaint);
canvas.restore();
}
https://gitee.com/lanyangyangzzz/android_ui
·················END················· 推荐阅读
• 耗时2年,Android进阶三部曲第三部《Android进阶指北》出版!
为了防止失联,欢迎关注我的小号
微信改了推送机制,真爱请星标本公号👇
评论