序文
新年から22 2020年2月は半月上で、まだないうちドアの、まだ一日三食の家に隠れ、まだホームオフィスで、再び手をまとめ、来週仕事に戻らないだろうかわかりません仕上げのノートのすべての種類を保存します
GitHubのフォローアップ関連コンテンツの更新が、私はスターを歓迎し、見て、見ることができるインパクト金と銀3人の4人の小さなパートナーにしたい
(引か左GitHubのリンク、あなたは自分自身を見つけることができる、そのようなインタビューなどの関連コンテンツへのアクセスを必要とします)
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)
A、ビューの描画処理フレームワーク
ビューは、反復の層から下にドローダウンされます。DecorView
- > ViewGroup
(---> ViewGroup
)- > View
上から下にこの方法によれば、配列中にmeasure
(測定)、 layout
(レイアウト)、 draw
(描画)
二、測定の流れ
名前が示すように、各コントロールのサイズを測定することです。
通話measure()
方法、論理処理の数、およびその呼onMeasure()
の呼び出しがする方法setMeasuredDimension()
ビュー、ビューのセット幅と高さの情報であるが、測定動作を完了する。
public final void measure(int widthMeasureSpec, int heightMeasur eSpec) {
}
measure()
この方法は、2つのパラメータを渡すとwidthMeasureSpec, heightMeasureSpec
、いくつかの情報を閲覧、幅と高さを表しています。
protected void onMeasure(int widthMeasureSpec, int heightMeasure Spec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumW idth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heig htMeasureSpec));
}
上記のプロセスのビューがMeasure
単純なプロセスで、重要な点はことであるwidthMeasureSpec
、heightMeasureSpec
これら2つのパラメータはどのような情報を取得するために?
我々が持っている場合widthMeasureSpec
、heightMeasureSpec
特定の処理によって導出表示幅/高さ、呼び出し(カスタム処理ステップ、書き換えることができる)setMeasuredDimension()
メソッド指定された幅と高さの表示、完全な測定を。
MeasureSpec
決定
最初の導入は何ですかMeasureSpec
?MeasureSpec
二つの部分、測定モードの一部で構成され、他方は測定大きいサイズである
小さいです。ここで、三種類にモードモード
UNSPECIFIED
:どのくらいくらいまでのいずれかの制限が表示されない、一般的に内部システムに使用
EXACTLY
:に対応し、これら2つのモードの具体的な数値。正確なサイズを検出することは、この時点でファイナルサイズがされ、ビューを必要な値で指定され、LayoutParams
match_parent
SpecSize
AT_MOST
:に対応。表示サイズは、親コンテナのサイズよりも大きくすることはできません。LayoutParams
wrap_content
だから、MeasureSpec
それがどのように決定するかですか?
ためDecorView
、画面の大きさ、及びそのレイアウトパラメータによって決定されますLayoutParams
。
この部分は簡単に記載されているLayoutParams
レイアウトフォーマット(のmatch_parent
、wrap_content
または指定された大きさ)、大きさ自体、および画面サイズに比べて、幅と高さが設定された画面サイズ、および対応するモードを超えません。(を含む他のビューのViewGroup
親のレイアウトによって決定される)、MeasureSpec
そのレイアウトパラメータLayoutParams
。この部分は、より複雑です。次のグラフは、異なる状況で:
子ビューのLayoutParams
レイアウトフォーマットはwrap_content
、親の大きさの残りのサブビュービューのサイズを確認し、配置することができmatch_parent
、サブ表示の大きさには違いありません。書き換えるために、通常、カスタムビューで、違いを示すためにonMeasure
取り扱い、方法をwrap_content
指定するためにするとき、ケースを。
ここではそれがから見てMeasureSpec
も、指定されたレイアウトの上部には、1層、親サブレイアウトインパクトのレイアウトを下るために開始します。
可能关于MeasureSpec
如何确定View大小还有些模糊,篇幅有限,没详细具体展开介绍
View的测量流程:
三、Layout流程
测量完View大小后,就需要将View布局在Window中,View的布局主要通过确定上 下左右四个点来确定的。
其中布局也是自上而下,不同的是ViewGroup
先在layout()
中确定自己的布局,然 后在onLayout()
方法中再调用子View的layout()
方法,让子View布局。在Measure 过程中,ViewGroup
一般是先测量子View的大小,然后再确定自身的大小。
public void layout(int l, int t, int r, int b) {
// 当前视图的四个顶点
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
// setFrame() / setOpticalFrame():确定View自身的位置
// 即初始化四个顶点的值,然后判断当前View大小和位置是否发生了变化并返回
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
//如果视图的大小和位置发生变化,会调用onLayout()
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PF LAG_LAYOUT_REQUIRED) {
// onLayout():确定该View所有的子View在父容器的位置
onLayout(changed, l, t, r, b);
...
}
上面看出通过 setFrame()
/ setOpticalFrame()
:确定View自身的位置,通过 onLayout()
确定子View的布局。 setOpticalFrame()
内部也是调用了 setFrame()
,所以具体看setFrame()
怎么确定自身的位置布局。
protected boolean setFrame(int left, int top, int right, int bot tom) {
...
// 通过以下赋值语句记录下了视图的位置信息,即确定View的四个顶点
// 即确定了视图的位置
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;
mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBott om);
}
确定了自身的位置后,就要通过onLayout()
确定子View的布局。onLayout()
是一个 可继承的空方法。
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
如果当前View就是一个单一的View,那么没有子View,就不需要实现该方法。
如果当前View是一个ViewGroup
,就需要实现onLayout
方法,该方法的实现个自 定义ViewGroup
时其特性有关,必须自己实现。
由此便完成了一层层的的布局工作。 View的布局流程:
四、Draw过程
View的绘制过程遵循如下几步:
①绘制背景 background.draw(
canvas
)
②绘制自己(onDraw
)
③绘制Children(dispatchDraw
)
④绘制装饰(onDrawScrollBars
)
从源码中可以清楚地看出绘制的顺序。
public void draw(Canvas canvas) {
// 所有的视图最终都是调用 View 的 draw ()绘制视图( ViewGroup 没有复写 此方法)
// 在自定义View时,不应该复写该方法,而是复写 onDraw(Canvas) 方法进行绘 制。
// 如果自定义的视图确实要复写该方法,那么需要先调用 super.draw(canvas)完 成系统的绘制,然后再进行自定义的绘制。
...
int saveCount;
if (!dirtyOpaque) {
// 步骤1: 绘制本身View背景
drawBackground(canvas);
}
// 如果有必要,就保存图层(还有一个复原图层)
// 优化技巧:
// 当不需要绘制 Layer 时,“保存图层“和“复原图层“这两步会跳过
// 因此在绘制的时候,节省 layer 可以提高绘制效率
final int viewFlags = mViewFlags;
if (!verticalEdges && !horizontalEdges) {
if (!dirtyOpaque)
// 步骤2:绘制本身View内容 默认为空实现, 自定义View时需 要进行复写
onDraw(canvas);
......
// 步骤3:绘制子View 默认为空实现 单一View中不需要实现,ViewG roup中已经实现该方法
dispatchDraw(canvas);
........
// 步骤4:绘制滑动条和前景色等等
onDrawScrollBars(canvas);
..........
return;
}
...
}
无论是ViewGroup
还是单一的View,都需要实现这套流程,不同的是,在 ViewGroup
中,实现了 dispatchDraw()
方法,而在单一子View中不需要实现该方 法。自定义View一般要重写onDraw()
方法,在其中绘制不同的样式。
View绘制流程:
五、总结
从View的测量、布局和绘制原理来看,要实现自定义View,根据自定义View的种 类不同,可能分别要自定义实现不同的方法。但是这些方法不外乎:onMeasure()
方法,onLayout()
方法,onDraw()
方法。
onMeasure()
方法: 单一View,一般重写此方法,针对wrap_content
情况,规定 View默认的大小值,避免于match_parent情况一致。ViewGroup
,若不重写,就会 执行和单子View中相同逻辑,不会测量子View。一般会重写onMeasure()
方法,循 环测量子View。
onLayout()
方法: 单一View,不需要实现该方法。ViewGroup
必须实现,该方法是 个抽象方法,实现该方法,来对子View进行布局。
onDraw()
方法: 无论单一View,或者ViewGroup
都需要实现该方法,因其是个空 方法
自己整理的983页面试大全,为打算面试或者正在面试的人提供借鉴的思路
上图知识汇总的PDF相关内容后续GitHub更新,想冲击金三银四的小伙伴可以找找看看,欢迎star
(顺手留下GitHub链接,需要获取相关面试等内容的可以自己去找)
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)