自定义View入门——NO.1
自定义View实例
学习自定义TextView
,熟悉流程。
晓注意:
系统有的属性,我们不能重新定义,比如TextView
的background
.
sp2px:TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());
自定义View基线计算
基线的计算方式:
top是个负值,bottom是个正值 baseline到文字顶部或底部的距离
Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
int dy = (fontMetrics.bottom - fontMetrics.top)/2 - fontMetrics.bottom;
int baseLine = getHeight/2 +dy;
源码课堂:
Q:如果自定义View继承LinearLayout
,还能出效果吗?
A:画的方法其实是draw(Canvas canvas)
if(!dirtyOpaque) onDraw(canvas)
dispatchDraw(canvas)
当dirtyOpaque
为false
时,才会出现。 其实dirtyOpaque
由mPrivateFlags
决定。
mPrivateFlags
是在View
的构造函数中调用computeOpaqueFlags
方法赋值
参考链接:https://www.jianshu.com/p/473185d29218
S:自定义View
中实现dispatchDraw
方法;
可以设置一个透明背景(前提是没有使用background
)
在构造方法中调用setWillNotDraw(false)
;
自定义View课堂
源码课堂1:
为什么要调用invalidate()
源码分析?
1>invalidateInternal();
2>ViewParent p = mParent;
p.invalidateChild(this,damage);
3>进入ViewGroup
类,搜索invalidateChild
方法,此时ViewParent
为ViewGroup
4>parent = parent.invalidateChildInParent(location,dirty);
…测量,布局,绘制等方法…
最后,调用mView.draw(canvas);
该方法中调用onDraw(canvas),dispatchDraw(canvas)等
源码课堂2:
为什么子线程不能更新UI?
获取到请求结果后,开启线程,更新UI,一般会调用setText(),setImageView()
等,此时都会调用ViewRootImpl
中的checkThread()
,用来检测线程if(mThread != Thread.currentThread())
。其中Thread.currentThread()
是子线程,mThead
在构造函数中通过Thread.currentThead
来初始化(可以认为是主线程),不是同一个线程。
自定义View过度渲染
为什么会出现过度渲染?
获取数据后,调用setText(),setImageView()
会调用invalidate()
,牵扯到过多的布局。
如何像Wx朋友圈一样优化过度渲染?
首先,打开手机开发者选项中的调试GPU过度绘制,红色代表过度绘制。
1.网上的解决方案
尽量不要嵌套
不要设置背景
2.最好的解决方案
不管是文字还是图片,自己去画,不要用系统的嵌套布局。这样运行效率高,但实现功能的效率低,需要公司以及个人去抉择。
备注:第二篇笔记,参考辉哥视频。