之前做的案例,包含view,viewGroup,动画,还有他们的综合应用
自定义view,滑动效果
1. 从0到1:Android自定义View打造沉浸式FM收音机刻度滑动控件本文将带你实现一个高度定制化的收音机刻度滑动 - 掘金
2. Android 自定义view 高级UI实战:打造丝滑3D循环滚轮时间选择器这个视图实现了一个可以循环滚动的选择器 - 掘金
自定义viewGroup
3. Android 流式布局打造热门标签 让RecyclerView颤抖!自研流式布局的架构设计与性能突围 - 掘金
4. Android 用户狂赞的UI特效!揭秘折叠卡片+流光动画的终极实现方案高仿:来自鸿蒙智行,华为问界的智仓系统,语 - 掘金
动画:混合动画
5. Android UI动效新标杆:灵动岛动画,动效深度体验!最近换了个新手机,看了下灵动岛动画还是挺炫丽的! 网上 - 掘金
6.android Vivo手机 指纹解锁动画 (附源码)最近换了个新手机,看了下指纹解锁动画还是挺炫丽的! 网上找了 - 掘金
自定义view和动画的综合应用:
7. Android AI大模型 文本打字机效果 流畅光标追踪与智能滚动大模型最近很火,deepSeek, 豆包 - 掘金
8.Android Vivo X200S手机充电动画 PK 遥遥领先Huawei手机充电动画最近换了个新手机VIVO - 掘金
高级UI主要涉及9个方面,如下
1.如何自定义view
2.如何自定义ViewGroup
3.如何做动画效果
4.如何写测量onMeasure
5.如何写绘制ondraw
6.如何写绘制onLayout
7.如何实现滑动,滚动
8.如何实现惯性滑动
9.常用的计算

1. 如何自定义 View
步骤:
- 继承 View 类 :创建类继承
android.view.View
。 - 重写构造方法 :处理 XML 属性(通过
obtainStyledAttributes
)。 - 实现
onMeasure()
:计算 View 的尺寸(处理wrap_content
)。 - 实现
onDraw()
:使用Canvas
和Paint
绘制内容。 - 处理触摸事件 :重写
onTouchEvent()
(可选)。
示例代码:
scss
public class CircleView extends View {
private Paint paint;
public CircleView(Context context) {
super(context);
init();
}
private void init() {
paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = 200; // 默认尺寸
setMeasuredDimension(
resolveSize(size, widthMeasureSpec),
resolveSize(size, heightMeasureSpec)
);
}
@Override
protected void onDraw(Canvas canvas) {
int center = getWidth() / 2;
canvas.drawCircle(center, center, center, paint);
}
}

2. 如何自定义 ViewGroup
步骤:
- 继承 ViewGroup 类 (如
LinearLayout
)。 - 重写
onMeasure()
:遍历子 View 并测量(measureChild
)。 - 重写
onLayout()
:调用子 View 的layout()
确定位置。 - 处理子 View 的 Margin :使用
MarginLayoutParams
。
示例代码:
java
public class CustomLayout extends ViewGroup {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec); // 测量所有子View
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
View child = getChildAt(0);
child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
}
}
3. 如何做动画效果

方法:
-
属性动画(推荐):
iniObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", 0f, 100f); anim.setDuration(1000); anim.start();
-
补间动画(视觉位移,不影响实际位置):
iniAnimation anim = new TranslateAnimation(0, 100, 0, 0); anim.setDuration(1000); view.startAnimation(anim);
-
在
onDraw()
中实现动画 :结合ValueAnimator
更新变量并调用invalidate()
。
4. 如何写测量 onMeasure
关键点:
- 解析
MeasureSpec
(模式:EXACTLY
,AT_MOST
,UNSPECIFIED
)。 - 处理
wrap_content
的默认尺寸。 - 调用
setMeasuredDimension()
保存结果。
示例:
ini
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int desiredWidth = 100; // wrap_content 时的默认宽度
int finalWidth;
if (widthMode == MeasureSpec.EXACTLY) {
finalWidth = widthSize; // 固定值或 match_parent
} else if (widthMode == MeasureSpec.AT_MOST) {
finalWidth = Math.min(desiredWidth, widthSize); // wrap_content
} else {
finalWidth = desiredWidth;
}
// 类似方式计算高度
setMeasuredDimension(finalWidth, finalHeight);
}
5. 如何写绘制 onDraw
步骤:
- 使用
Canvas
绘制图形(圆、矩形、路径等)。 - 通过
Paint
控制样式(颜色、描边、抗锯齿)。 - 考虑
Padding
(避免内容紧贴边缘)。
示例:
scss
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
// 考虑 padding
int left = getPaddingLeft();
int top = getPaddingTop();
int right = getWidth() - getPaddingRight();
int bottom = getHeight() - getPaddingBottom();
canvas.drawRect(left, top, right, bottom, paint);
}
6. 如何写布局 onLayout
(ViewGroup)
作用: 确定子 View 的位置和大小。
示例:
ini
@Override
protected void onLayout(boolean changed, int parentLeft, int parentTop, int parentRight, int parentBottom) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
// 计算子 View 的位置(例如垂直排列)
int left = 0;
int top = i * 100;
int right = left + child.getMeasuredWidth();
int bottom = top + child.getMeasuredHeight();
child.layout(left, top, right, bottom);
}
}
7. 如何实现滑动/滚动

方法:
-
使用
scrollTo
/scrollBy
(内容滑动,非 View 本身移动):scss// 向右滑动 50px(内容向左移动) scrollBy(50, 0);
-
结合
Scroller
平滑滑动:scssScroller scroller = new Scroller(context); // 开始滑动 scroller.startScroll(getScrollX(), 0, 100, 0, 500); invalidate(); @Override public void computeScroll() { if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); } }
8. 如何实现惯性滑动
步骤:
-
使用
VelocityTracker
获取滑动速度。 -
Scroller.fling()
模拟惯性:scssVelocityTracker velocityTracker = VelocityTracker.obtain(); // 在 onTouchEvent() 中追踪速度 @Override public boolean onTouchEvent(MotionEvent event) { velocityTracker.addMovement(event); switch (event.getAction()) { case MotionEvent.ACTION_UP: velocityTracker.computeCurrentVelocity(1000); // 单位:像素/秒 int velocityX = (int) velocityTracker.getXVelocity(); scroller.fling( getScrollX(), getScrollY(), -velocityX, 0, // 注意方向取反 minX, maxX, minY, maxY ); invalidate(); velocityTracker.recycle(); break; } return true; }
-
在
computeScroll()
中更新位置(同步骤7)。
9.常用计算与图形算法
(1) 贝塞尔曲线 (Bezier Curve)
应用场景:平滑路径绘制、弹性动画、手势轨迹
scss
// 二次贝塞尔曲线
Path path = new Path();
path.moveTo(startX, startY);
path.quadTo(controlX, controlY, endX, endY);
canvas.drawPath(path, paint);
// 三次贝塞尔曲线
path.cubicTo(controlX1, controlY1, controlX2, controlY2, endX, endY);
(2) 三角函数
应用场景:圆形布局、旋转动画、角度计算
ini
// 计算圆周上点的位置
float centerX = getWidth()/2f;
float centerY = getHeight()/2f;
float radius = 100f;
float angle = (float) (Math.PI * 0.75); // 135度
float x = centerX + radius * (float) Math.cos(angle);
float y = centerY + radius * (float) Math.sin(angle);
(3) 向量运算
应用场景:手势方向判断、物理动画
ini
// 计算两点间向量
float dx = point2.x - point1.x;
float dy = point2.y - point1.y;
// 向量长度(距离)
float distance = (float) Math.sqrt(dx * dx + dy * dy);
// 向量标准化
if (distance > 0) {
float unitX = dx / distance;
float unitY = dy / distance;
}
(4) 颜色计算
应用场景:渐变动画、状态切换
ini
// 颜色插值(线性渐变)
float fraction = currentProgress / maxProgress;
int color = (int) (startColor + fraction * (endColor - startColor));
// HSV颜色空间转换(色相旋转)
float[] hsv = new float[3];
Color.colorToHSV(baseColor, hsv);
hsv[0] = (hsv[0] + 30) % 360; // 色相偏移30度
int newColor = Color.HSVToColor(hsv);
(5) 几何计算
应用场景:碰撞检测、区域判断
ini
// 点是否在圆内
boolean inCircle = (pointX - centerX) * (pointX - centerX)
+ (pointY - centerY) * (pointY - centerY)
<= radius * radius;
// 点是否在矩形内
Rect rect = new Rect(left, top, right, bottom);
boolean inRect = rect.contains(pointX, pointY);
(6) 插值器 (Interpolator)
应用场景:动画非线性变化
java
// 自定义插值器
public class BounceInterpolator implements Interpolator {
@Override
public float getInterpolation(float input) {
return (float) (Math.sin(input * Math.PI * 2) * 0.5 + 0.5);
}
}
// 使用
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationY", 0, 100);
anim.setInterpolator(new BounceInterpolator());
(7) 路径测量 (PathMeasure)
应用场景:沿路径运动、路径长度计算
ini
Path path = new Path();
path.addCircle(centerX, centerY, radius, Path.Direction.CW);
PathMeasure pm = new PathMeasure(path, false);
float pathLength = pm.getLength();
// 获取路径上的点
float[] pos = new float[2];
float distance = pathLength * fraction; // 路径百分比
pm.getPosTan(distance, pos, null);
(8) 矩阵变换 (Matrix)
应用场景:图像变换、多点触控
scss
Matrix matrix = new Matrix();
// 组合变换
matrix.postTranslate(dx, dy);
matrix.postRotate(degrees, pivotX, pivotY);
matrix.postScale(scaleX, scaleY, pivotX, pivotY);
// 应用到Canvas
canvas.save();
canvas.concat(matrix);
// 绘制内容...
canvas.restore();
10 总结:
- 所有自定义View必须实现
onMeasure
和onDraw
- ViewGroup额外需要
onLayout
处理子视图 - 动画效果通过修改属性驱动
onDraw
- 滑动效果依赖
Scroller
+computeScroll
机制 - 高级效果基于数学工具库的计算结果
- 惯性滑动=触摸事件+速度追踪+Scroller