揭秘Android視圖繪制的流程步驟
什么是View?
View是Android系統(tǒng)中的一個基本組件,它是用戶界面上的一個矩形區(qū)域,可以用來展示文本、圖片、按鈕等等。View可以響應(yīng)用戶的交互事件,比如點擊、滑動等等。在Android中,所有的UI組件都是繼承自View類。
View的繪制過程
View的繪制過程可以分為三個階段:測量、布局和繪制。下面我們將逐一介紹這三個階段。
測量階段(Measure)
測量階段是View繪制過程的第一個重要階段。在測量階段,系統(tǒng)會調(diào)用View的onMeasure
方法,測量View的寬度和高度。在這個過程中,系統(tǒng)會根據(jù)View的LayoutParams和父容器的大小來計算出View的大小。
例:下面代碼是一個自定義View的onMeasure方法例程。在測量過程中,我們設(shè)定了View的大小。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 獲取寬度的Size和Mode int widthSize = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); // 如果Mode是精確的,直接返回 if (widthMode == MeasureSpec.EXACTLY) { setMeasuredDimension(widthSize, heightMeasureSpec); return; } // 計算View的寬度 int desiredWidth = getPaddingLeft() + getPaddingRight() + defaultWidth; int measuredWidth; if (desiredWidth < widthSize) { measuredWidth = desiredWidth; } else { measuredWidth = widthSize; } // 設(shè)置寬度和高度的Size和Mode int heightSize = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int measuredHeight = defaultHeight; if (heightMode == MeasureSpec.EXACTLY) { measuredHeight = heightSize; } else if (heightMode == MeasureSpec.AT_MOST) { measuredHeight = Math.min(defaultHeight, heightSize); } setMeasuredDimension(measuredWidth, measuredHeight); }
在測量階段結(jié)束后,系統(tǒng)會將計算好的寬度和高度傳遞給布局階段。
布局階段(Layout)
布局階段是View繪制過程的第二個重要階段。在布局階段,系統(tǒng)會調(diào)用View的onLayout
方法,將View放置在父容器中的正確位置。在這個過程中,系統(tǒng)會根據(jù)View的LayoutParams和父容器的位置來確定View的位置。
例:下面代碼是一個自定義ViewGroup的onLayout方法例程。在布局過程中,我們遍歷子View,并根據(jù)LayoutParams確定子View的位置和大小。
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int count = getChildCount(); int left = getPaddingLeft(); int top = getPaddingTop(); int right = getMeasuredWidth() - getPaddingRight(); int bottom = getMeasuredHeight() - getPaddingBottom(); for (int i = 0; i < count; i++) { View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } LayoutParams lp = (LayoutParams) child.getLayoutParams(); int childLeft = left + lp.leftMargin; int childTop = top + lp.topMargin; int childRight = right - lp.rightMargin; int childBottom = bottom - lp.bottomMargin; child.layout(childLeft, childTop, childRight, childBottom); } }
繪制階段(Draw)
繪制階段是View繪制過程的最后一個重要階段。在繪制階段,系統(tǒng)會調(diào)用View的onDraw
方法,繪制View的內(nèi)容。在這個過程中,我們可以使用Canvas對象來繪制各種形狀、文本和圖片等等。
例:下面代碼是一個自定義View的onDraw方法例程。在繪制過程中,我們使用Paint對象繪制了一段文本。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //繪制文本 String text = "Hello World"; Paint paint = new Paint(); paint.setTextSize(50); paint.setColor(Color.RED); paint.setAntiAlias(true); canvas.drawText(text, 0, getHeight() / 2, paint); }
除了繪制內(nèi)容,我們還可以在繪制階段繪制View的背景和前景。系統(tǒng)會調(diào)用drawBackground
和drawForeground
方法來繪制背景和前景。值得注意的是,View的繪制順序是:先繪制背景,再繪制內(nèi)容,最后繪制前景。
View的繪制流程
View的繪制流程可以看作是一個遞歸調(diào)用的過程,下面我們將具體介紹這個過程。
Step 1:創(chuàng)建View
在View繪制過程的開始階段,我們需要創(chuàng)建一個View對象,并將它添加到父容器中。在這個過程中,系統(tǒng)會調(diào)用View的構(gòu)造函數(shù),并將View的LayoutParams傳遞給它。
Step 2:測量View
接下來,系統(tǒng)會調(diào)用View的measure
方法,測量View的寬度和高度。在這個過程中,View會根據(jù)自身的LayoutParams和父容器的大小來計算出自己的寬度和高度。
Step 3:布局View
在測量完成后,系統(tǒng)會調(diào)用View的layout
方法,將View放置在父容器中的正確位置。在這個過程中,View會根據(jù)自身的LayoutParams和父容器的位置來確定自己的位置。
Step 4:繪制背景
在布局完成后,系統(tǒng)會調(diào)用View的drawBackground
方法,繪制View的背景。在這個過程中,我們可以使用Canvas對象來繪制各種形狀、文本和圖片等等。
Step 5:繪制內(nèi)容
接下來,系統(tǒng)會調(diào)用View的onDraw
方法,繪制View的內(nèi)容。在這個過程中,我們可以使用Canvas對象來繪制各種形狀、文本和圖片等等。
Step 6:繪制前景
在繪制內(nèi)容完成后,系統(tǒng)會調(diào)用View的drawForeground
方法,繪制View的前景。在這個過程中,我們同樣可以使用Canvas對象來繪制各種形狀、文本和圖片等等。
Step 7:繪制子View
接著,系統(tǒng)會遞歸調(diào)用ViewGroup的dispatchDraw
方法,繪制所有子View的內(nèi)容。在這個過程中,我們可以使用Canvas對象來繪制各種形狀、文本和圖片等等。
Step 8:完成繪制
最后,所有的View繪制完成,整個View樹也就繪制完成。
例:下面代碼是一個自定義ViewGroup的繪制流程例程。在繪制過程中,我們先畫背景,再繪制每個子View的內(nèi)容。
public class MyViewGroup extends ViewGroup { public MyViewGroup(Context context) { super(context); } public MyViewGroup(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 測量子View的寬高 measureChildren(widthMeasureSpec, heightMeasureSpec); // 獲取ViewGroup的寬高大小 int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); // 設(shè)置ViewGroup的寬高 setMeasuredDimension(widthSize, heightSize); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 遍歷所有子View,設(shè)置它們的位置和大小 int childCount = getChildCount(); int left, top, right, bottom; for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); left = childView.getLeft(); top = childView.getTop(); right = childView.getRight(); bottom = childView.getBottom(); childView.layout(left, top, right, bottom); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 畫背景 canvas.drawColor(Color.WHITE); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); // 繪制每個子View的內(nèi)容 for (int i = 0; i < getChildCount(); i++) { View childView = getChildAt(i); childView.draw(canvas); } } }
在ViewGroup的繪制流程中,系統(tǒng)會先調(diào)用ViewGroup的draw
方法,然后依次調(diào)用dispatchDraw
方法和繪制每個子View的draw
方法。ViewGroup的繪制順序是先繪制自己的背景,再繪制每個子View的內(nèi)容和背景,最后繪制自己的前景。
總結(jié)
本文詳細(xì)介紹了Android View的繪制過程,包括測量階段、布局階段和繪制階段。同時,我們還在代碼實現(xiàn)的角度,詳細(xì)說明了Android ViewGroup的繪制流程,幫助你更好地理解和掌握Android的UI開發(fā)。
以上就是揭秘Android視圖繪制的流程步驟的詳細(xì)內(nèi)容,更多關(guān)于Android 視圖繪制的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
android RecyclerView的一些優(yōu)化點介紹
大家好,本篇文章主要講的是android RecyclerView的一些優(yōu)化點介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12總結(jié)Android App內(nèi)存優(yōu)化之圖片優(yōu)化
網(wǎng)上有很多大拿分享的關(guān)于Android性能優(yōu)化的文章,主要是通過各種工具分析,使用合理的技巧優(yōu)化APP的體驗,提升APP的流暢度,但關(guān)于內(nèi)存優(yōu)化的文章很少有看到。下面是我在實踐過程中使用的一些方法,很多都是不太成熟的項目,只是將其作為一種處理方式分享給大家。2016-08-08Android studio 2020中的Android SDK 下載教程
這篇文章主要介紹了Android studio 2020中的Android SDK 下載教程,本文圖文并茂給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03Android的Activity跳轉(zhuǎn)動畫各種效果整理
Android的Activity跳轉(zhuǎn)就是很生硬的切換界面。其實Android的Activity跳轉(zhuǎn)可以設(shè)置各種動畫,本文整理了一些,還有很多動畫效果,就要靠我們發(fā)揮自己的想象力2013-06-06Android GPS室內(nèi)定位問題的解決方法(location為null)
這篇文章主要為大家詳細(xì)介紹了Android GPS室內(nèi)定位問題的解決方法,location為null,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-02-02