1、ViewGroup为什么不会执行onDraw?
- 1、View.draw(是DecorView);
- 2、View.java类中,调用onDraw(canvas)和dispatchDraw(canvas);
- 3、dispatchDraw(canvas)其实调用的是ViewGroup.dispatchDraw();
- 4、ViewGroup.dispatchDraw()里面会执行drawChild(canvas,child,drawingTime);
- 5、View.java类中,进入drawChild()里面,会中View.draw()三个参数的方法();
- 6、View.java类中,会调用updateDisplayListIfDirty()->dispatchDraw(canvas);
2、文字变色
需求:类似播放音乐文字变色功能
![](https://img.haomeiwen.com/i26777047/44a14d552de7ddbf.png)
1、自定义文字变色步骤
- 1.自定义属性,以及xml中使用
- 2.测量 --- 只需要测量自己
- 3.onDraw:绘制自己
- 4.交互
2、调用MainActivity
public class MainActivity extends AppCompatActivity {
private ColorTrackTextView mColorTrackTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mColorTrackTextView = findViewById(R.id.color_track_tv);
}
public void leftToRight(View view) {
setAnimation(ColorTrackTextView.Direction.LEFT_TO_RIGHT);
}
public void rightToLeft(View view) {
setAnimation(ColorTrackTextView.Direction.RIGHT_TO_LEFT);
}
public void setAnimation(ColorTrackTextView.Direction direction) {
mColorTrackTextView.setDirection(direction);
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 1);
valueAnimator.setDuration(2000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentProgress = (float) animation.getAnimatedValue();
mColorTrackTextView.setCurrentProgress(currentProgress);
}
});
valueAnimator.start();
}
3、activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.leo.colortrackview.ColorTrackTextView
android:id="@+id/color_track_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="20sp"
app:changeColor="@color/teal_200" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="leftToRight"
android:text="左到右" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="rightToLeft"
android:text="右到左" />
</LinearLayout>
4、ColorTrackTextView
package com.leo.colortrackview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
public class ColorTrackTextView extends AppCompatTextView {
// 绘制不变色字体的画笔
private Paint mOriginPaint;
// 绘制变色字体的画笔
private Paint mChangePaint;
// 当前变色的进度
private float mCurrentProgress = 0.5f;
// 实现不同朝向
private Direction mDirection;
public enum Direction {
LEFT_TO_RIGHT, RIGHT_TO_LEFT
}
public ColorTrackTextView(@NonNull Context context) {
this(context, null);
}
public ColorTrackTextView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ColorTrackTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint(context, attrs);
}
private void initPaint(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ColorTrackTextView);
int originColor = typedArray.getColor(R.styleable.ColorTrackTextView_originColor,
getTextColors().getDefaultColor());
int changeColor = typedArray.getColor(R.styleable.ColorTrackTextView_changeColor,
getTextColors().getDefaultColor());
// 回收
typedArray.recycle();
// 不变色的画笔
mOriginPaint = getPaintByColor(originColor);
// 变色的画笔
mChangePaint = getPaintByColor(changeColor);
}
/**
* 根据颜色获取画笔
*/
private Paint getPaintByColor(int color) {
Paint paint = new Paint();
// 设置颜色
paint.setColor(color);
// 设置抗锯齿
paint.setAntiAlias(true);
// 防抖动
paint.setDither(true);
// 设置字体的大小 就是TextView的字体大小
paint.setTextSize(getTextSize());
return paint;
}
@Override
protected void onDraw(Canvas canvas) {
int currentPoint = (int) (mCurrentProgress * getWidth());
// 从左边到右边变色
if (mDirection == Direction.LEFT_TO_RIGHT) {
// 绘制变色的部分 -- 开始 currentPoint = 0;结束 currentPoint = getWidth
drawText(canvas, mChangePaint, 0, currentPoint);
// 绘制不变色的部分
drawText(canvas, mOriginPaint, currentPoint, getWidth());
} else {
// 绘制变色的部分 -- 开始 currentPoint = getWidth;结束 currentPoint = 0
drawText(canvas, mChangePaint, getWidth() - currentPoint, getWidth());
// 绘制不变色的部分
drawText(canvas, mOriginPaint, 0, getWidth() - currentPoint);
}
}
private void drawText(Canvas canvas, Paint paint, int start, int end) {
canvas.save();
Rect rect = new Rect(start, 0, end, getHeight());
canvas.clipRect(rect);
String text = getText().toString();
// 判空
if (TextUtils.isEmpty(text)) return;
// 获取文字的区域
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
// 获取x坐标
int dx = getWidth() / 2 - bounds.width() / 2;
// 获取基线 baseLine
Paint.FontMetricsInt fontMetricsInt = mChangePaint.getFontMetricsInt();
int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
int baseLine = getHeight() / 2 + dy;
// 绘制文字
canvas.drawText(text, dx, baseLine, paint);
canvas.restore();
}
public void setCurrentProgress(float currentProgress) {
this.mCurrentProgress = currentProgress;
invalidate();
}
public void setDirection(Direction direction) {
this.mDirection = direction;
}
}
![](https://img.haomeiwen.com/i26777047/389341f3a416fc7d.png)
5、attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ColorTrackTextView">
<attr name="originColor" format="color" />
<attr name="changeColor" format="color" />
</declare-styleable>
</resources>
![](https://img.haomeiwen.com/i26777047/69da875c90f3b3d9.png)
3、自定义FlowLayout
1、FlowLayout
package com.leo.flowlayout;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public class FlowLayout extends ViewGroup {
private List<View> mLineViews;//每一行的子View
private List<List<View>> mViews;//所有的行 一行一行的存储
private List<Integer> mHeights;//每一行的高度
public FlowLayout(Context context) {
this(context, null);
}
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mLineViews = new ArrayList<>();
mViews = new ArrayList<>();
mHeights = new ArrayList<>();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 获取限制的值
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// 记录当前行的宽度和高度
int lineWidth = 0;// 宽度是当前行子view的宽度之和
int lineHeight = 0;// 高度是当前行所有子View中高度的最大值
//整个流式布局的宽度和高度
int flowLayoutWidth = 0;//所有行中宽度的最大值
int flowLayoutHeight = 0;// 所以行的高度的累加
init();
int childCount = this.getChildCount();
// 先测量子View,再根据子View尺寸,计算自己的
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
//获取到当前子View的测量的宽度/高度
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
// 已经放入的孩子的宽度 + 准备放入的孩子的宽度 大于 总宽度 就换行
if (lineWidth + childWidth > widthSize) {
mViews.add(mLineViews);
mLineViews = new ArrayList<>();//创建新的一行
// 所有行中 最宽的一行 作为 流式布局的宽
flowLayoutWidth = Math.max(flowLayoutWidth, lineWidth);
// 流式布局的高度为所有行的高度相加
flowLayoutHeight += lineHeight;
mHeights.add(lineHeight);
lineWidth = 0;
lineHeight = 0;
}
mLineViews.add(child);
lineWidth += childWidth;
// 获取行中最高的子View
lineHeight = Math.max(lineHeight, childHeight);
}
// 保存尺寸给后面用
setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : flowLayoutWidth
, heightMode == MeasureSpec.EXACTLY ? heightSize : flowLayoutHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int currX = 0;
int currY = 0;
int lineCount = mViews.size();
// 处理每一行
for (int i = 0; i < lineCount; i++) {
List<View> lineViews = mViews.get(i);
int lineHeight = mHeights.get(i);
int size = lineViews.size();
// 处理每一行中的View
for (int j = 0; j < size; j++) {
View child = lineViews.get(j);
// 子View的左上右下
int left = currX;
int top = currY;
int right = left + child.getMeasuredWidth();
int bottom = top + child.getMeasuredHeight();
// 布局子View
child.layout(left, top, right, bottom);
currX += child.getMeasuredWidth();
}
currY += lineHeight;
currX = 0;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.leo.flowlayout.FlowLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mFlowLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp">
<Button
android:layout_width="wrap_content"
android:layout_height="55dp"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="一行一个元素生活不止眼前的苟且,还有诗和远方大法师的打分sad发送到发送到发的发送到发送到第三方阿萨德佛挡杀佛但是" />
<Button
android:layout_width="wrap_content"
android:layout_height="90dp"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小麻小儿郎呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="11一行一个元素生活不止眼前的苟且,还有诗和远方大法师的打分sad发送到发送到发的发送到发送到第三方阿萨德佛挡杀佛但是" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="85dp"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="生活不止眼前的苟且,还有诗和远方" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小麻小儿郎呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="45dp"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="75dp"
android:text="生活不止眼前的苟且,还有诗和远方" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小麻小儿郎呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="生活不止眼前的苟且,还有诗和远方" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="85dp"
android:text="小麻小儿郎呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="100dp"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="生活不止眼前的苟且,还有诗和远方" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小麻小儿郎呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="85dp"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="生活不止眼前的苟且,还有诗和远方" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小麻小儿郎呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="生活不止眼前的苟且,还有诗和远方" />
<Button
android:layout_width="wrap_content"
android:layout_height="85dp"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小麻小儿郎呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="65dp"
android:text="生活不止眼前的苟且,还有诗和远方" />
<Button
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小麻小儿郎呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="75dp"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="300dp"
android:text="生活不止眼前的苟且,还有诗和远方" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小麻小儿郎呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello hi ..." />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你是谁呀" />
<Button
android:layout_width="wrap_content"
android:layout_height="65dp"
android:layout_gravity="bottom"
android:text="人在他在,塔亡人亡" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="生活不止眼前的苟且,还有诗和远方1" />
<Button
android:layout_width="wrap_content"
android:layout_height="250dp"
android:text="发电房" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这是结束" />
</com.leo.flowlayout.FlowLayout>
</ScrollView>
网友评论