自定义view流程
自定义view流程
-
继承View,重写构造函数,两参数的 由系统自动调用
-
重写onMeasure(先执行)、onLayout(其次)、onDraw(最后执行)
-
声明自定义属性,在values目录下,新建attrs.xml文件
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="myViewAttrs"> <!--自定义属性--> <attr name="originColor" format="color"/> <attr name="changeColor" format="color"/> </declare-styleable> </resources>
-
在布局文件里就可以使用自定义属性了
<!--必须要声明xmlns:app 才能使用自定义属性--> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@ id/ll_nav" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <com.wow.modularization.MyTextView android:id="@ id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="变化前" android:gravity="center" android:textSize="20sp" app:changeColor="@android:color/holo_blue_light" app:originColor="@color/purple_200" /> </LinearLayout>
-
在两参的构造函数里获取自定义属性的值
int originColor, changeColor; public MyTextView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); // 获取自定义类型属性 数组 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myViewAttrs); originColor = typedArray.getColor(R.styleable.myViewAttrs_originColor, getTextColors().getDefaultColor()); changeColor = typedArray.getColor(R.styleable.myViewAttrs_changeColor, getTextColors().getDefaultColor()); typedArray.recycle(); // 回收资源 }
-
如果继承系统view(例如 TextView),系统view已经测量好了宽高,而你也不需要额外改变其尺寸,则可以不重写onMeasure()函数,只重写onDraw()函数最后就是自由发挥了
view绘制流程简版
构造函数(Context context) // 代码中new调用
构造函数(Context context, AttributeSet attrs) // 系统反射调用,xml解析是由 LayoutInflater.inflater处理的
构造函数(Context context, AttributeSet attrs, int defStyleAttr) // 主题 style
序列化(xml、json...) 就是自定义的格式数据串:用的多的是 IOT(物联网)
物联网:通常由蓝牙 传递数据 串口 协议。
View的绘制基本由measure()、layout()、draw()这个三个函数完成
函数 | 作用 | 相关方法 |
---|---|---|
measure() | 测量View的宽高 | measure(),setMeasuredDimension(),onMeasure() |
layout() | 计算当前View以及子View的位置 | layout(),onLayout(),setFrame() |
draw() | 视图的绘制工作 | draw(),onDraw() |
想象下:你有个大的毛坯房(ViewGroup),你会怎么做?
1、测量其尺寸大小(measure)
2、分出对应的房间布局(layout)
3、贴上好看的瓷砖,把房子画的漂漂亮亮(draw)
结论:
自定义view 主要实现 onMeasure(测量自身大小) onDraw
自定义ViewGroup 主要实现 onMeasure onLayout
measure()
重点:MeasureSpec
MeasureSpec
是View的内部类,它封装了一个View的尺寸,在onMeasure()
当中会根据这个MeasureSpec
的值来确定View的宽高。
MeasureSpec
的值保存在一个int值当中。一个int值有32位,前两位表示模式mode
后30位表示大小size
。即MeasureSpec
=mode
size
。
在MeasureSpec
当中一共存在三种mode:UNSPECIFIED
、EXACTLY
和 AT_MOST
。
对于View来说,MeasureSpec的mode和Size有如下意义
模式 | 意义 | 对应 |
---|---|---|
EXACTLY | 精准模式,View需要一个精确值,这个值即为MeasureSpec当中的Size | match_parent |
AT_MOST | 最大模式,View的尺寸有一个最大值,View不可以超过MeasureSpec当中的Size值 | wrap_content |
UNSPECIFIED | 无限制,View对尺寸没有任何限制,View设置为多大就应当为多大 | 一般系统内部使用 |
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 获取测量模式(Mode)
int specMode = MeasureSpec.getMode(measureSpec)
// 获取测量大小(Size)(父view给的大小)
int specSize = MeasureSpec.getSize(measureSpec)
// 通过Mode 和 Size 生成新的SpecMode
int measureSpec=MeasureSpec.makeMeasureSpec(size, mode);
}
子View的测量模式是由 自身LayoutParam和 父View的MeasureSpec来决定的。
setMeasuredDimension(int measuredWidth, int measuredHeight)
:该方法用来设置View的宽高,在我们自定义View时也会经常用到。
结合下图理解 MeasureSpec
getMeasureWidth 与 getWidth的区别
getMeasureWidth: 在measure() 过程结束后就可以获取到对应的值。 通过 setMeasuredDimension() 方法设置的
getWidth:在layout() 过程结束后才能获取到;通过视图右边的坐标减去左边的坐标计算出来的。
layout()
子view布局
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 对 子view 分配空间,相当与一个大平房,隔出了一个房间一样
int top = itemPaddingTop, i = 0, len = 0;
for (Integer count : lineCounts) {
int left = itemPaddingLeft, tempTop = 0;
len = count;
for (; i < len; i ) {
View view = lineViewsList.get(i);
view.layout(left, top, left view.getMeasuredWidth(), top view.getMeasuredHeight());
left = itemPaddingLeft view.getMeasuredWidth();
tempTop = Math.max(tempTop, view.getMeasuredHeight());
}
top = itemPaddingTop tempTop;
}
}
draw()
注意了:save() 保存的只是CanvasRenderingContext2D对象的状态以及对象的所有属性,并不包括这个对象上绘制的图形。所以 restore() 只是把canvas的状态还原了,而不会把 已经绘制的图形 也还原掉。
- save:用来保存最近一次的Canvas的状态和属性。
- restore:用来获取save保存的Canvas之前的状态和属性。防止save后对Canvas执行的平移、放缩、旋转、错切、裁剪等可以改变画布的操作对后续的绘制的影响。
save 进栈; restore 出栈
绘图工具类
private Scroller scroller; // 滑动工具
private VelocityTracker tracker; // 速率追踪器工具
private void init(Context ct){
context = ct;
scroller = new Scroller(ct);
tracker = VelocityTracker.obtain();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
tracker.addMovement(event); // 追踪
...
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
....
//scrollBy方法将对我们当前View的位置进行偏移
scrollBy(-deltaX, 0); // View方法 scrollTo(mScrollX x, mScrollY y);
break;
case MotionEvent.ACTION_UP:
...
tracker.computeCurrentVelocity(1000);
float xVelocity = tracker.getXVelocity();
...
tracker.clear();//清除 追踪
// scroller 工具 移动 回调computeScroll()
scroller.startScroll(
getScrollX(), // startX
getScrollY(), // startY
destX - getScrollX(), // dx
destY - getScrollY(), // dy
1000); // duration
invalidate();
break;
}
return true;
}
@Override
public void computeScroll() {
super.computeScroll();
if (scroller.computeScrollOffset()){
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgaikgc
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13