日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

JavaSwing基礎(chǔ)之Layout布局相關(guān)知識(shí)詳解

瀏覽:175日期:2022-08-12 09:20:17
目錄一、View layout方法二、ViewGroup layout方法三、自定義垂直布局VerticalLayout四、效果展示一、View layout方法

首先,還是從ViewRootImpl說(shuō)起,界面的繪制會(huì)觸發(fā)performMeasure、performLayout方法,而在performLayout方法中就會(huì)調(diào)用mView的layout方法開(kāi)始一層層View的布局工作。

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) { final View host = mView;host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); }

mView我們都知道了,就是頂層View——DecorView,那么就進(jìn)去看看DecorView的layout方法:

不好意思,DecorView中并沒(méi)有l(wèi)ayout方法...

所以,我們直接看看View的layout方法:

public void layout(int l, int t, int r, int b) { boolean changed = isLayoutModeOptical(mParent) ?setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { onLayout(changed, l, t, r, b);} } protected void onLayout(boolean changed, int left, int top, int right, int bottom) { } 首先,方法傳入了四個(gè)參數(shù),分別代表view的左、上、下、右四個(gè)值。 然后通過(guò)setOpticalFrame方法或者setFrame方法判斷布局參數(shù)是否改變。

具體判斷過(guò)程就是通過(guò)老的上下左右值和新的上下左右值進(jìn)行比較,邏輯就在setFrame方法中:

protected boolean setFrame(int left, int top, int right, int bottom) {boolean changed = false; if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { changed = true; // Remember our drawn bit int drawn = mPrivateFlags & PFLAG_DRAWN; int oldWidth = mRight - mLeft; int oldHeight = mBottom - mTop; int newWidth = right - left; int newHeight = bottom - top; boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); // Invalidate our old position invalidate(sizeChanged); mLeft = left; mTop = top; mRight = right; mBottom = bottom; mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);}return changed; }

如果上下左右有一個(gè)參數(shù)值發(fā)生了改變,就說(shuō)明這個(gè)View的布局發(fā)生了改變,然后重新計(jì)算View的寬度高度(newWidth、newHeight),并賦值了View新的上下左右參數(shù)值。

在這個(gè)layout方法中主要涉及到了四個(gè)參數(shù):mLeft、mTop、mBottom、mRight,分別代表了View的左坐標(biāo)、上坐標(biāo)、下坐標(biāo)和右坐標(biāo),你可以把View理解為一個(gè)矩形,確定了這四個(gè)值,就能確定View矩形的四個(gè)頂點(diǎn)值,也就能確定View在畫(huà)布中的具體位置。

所以,layout方法到底干了啥?

就是傳入上下左右值、然后賦值上下左右值、完畢。

然后我們就可以根據(jù)這些值獲取View的一系列參數(shù),比如View寬度:

public final int getWidth() {return mRight - mLeft; }

至此,View的layout方法就結(jié)束了,主要就是通過(guò)對(duì)上下左右參數(shù)的賦值完成對(duì)View的布局,非常簡(jiǎn)單。

下面看看ViewGroup。

二、ViewGroup layout方法

@Override public final void layout(int l, int t, int r, int b) {if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) { if (mTransition != null) {mTransition.layoutChange(this); } super.layout(l, t, r, b);} else { mLayoutCalledWhileSuppressed = true;} }

額,還是調(diào)用到View的layout方法,難道說(shuō)ViewGroup和View的布局過(guò)程是一樣的,就是確定了本身的位置?

那ViewGroup的子View怎么辦呢?不急,我們剛才說(shuō)layout方法的時(shí)候還漏了一個(gè)onLayout方法,只不過(guò)這個(gè)方法在View里面是空實(shí)現(xiàn),而到了ViewGroup中變成了一個(gè)抽象方法:

@Override protected abstract void onLayout(boolean changed, int l, int t, int r, int b);

也就是任何ViewGroup都必須實(shí)現(xiàn)這個(gè)方法,來(lái)完成對(duì)子View的布局?jǐn)[放。

具體的布局?jǐn)[放邏輯就是在onLayout方法中一個(gè)個(gè)調(diào)用子View的layout方法,然后完成每個(gè)子View的布局,最終完成繪制工作。

接下來(lái)我們就來(lái)自己實(shí)現(xiàn)一個(gè)垂直線(xiàn)性布局(類(lèi)似LinearLayout),正好復(fù)習(xí)下上一節(jié)的onMearsure和這一節(jié)的onLayout。

三、自定義垂直布局VerticalLayout

首先,我們要確定我們這個(gè)自定義ViewGroup的作用,是類(lèi)似垂直方向的LinearLayout功能,在該ViewGroup下的子View可以按垂直線(xiàn)性順序依次往下排放。我們給它起個(gè)名字叫VerticalLayout~

繼承ViewGroup

首先,我們這個(gè)布局肯定要繼承自ViewGroup,并且實(shí)現(xiàn)相應(yīng)的構(gòu)造方法:

public class VerticalLayout : ViewGroup { constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(context,attrs,defStyleAttr ) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { }}

重寫(xiě)generateLayoutParams方法

自定義ViewGroup還需要重寫(xiě)的一個(gè)方法是generateLayoutParams,這一步是為了讓我們的ViewGroup支持Margin,后續(xù)我們就可以通過(guò)MarginLayoutParams來(lái)獲取子View的Margin值。

override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams? {return MarginLayoutParams(context, attrs) }

重寫(xiě)測(cè)量方法onMeasure

然后,我們需要對(duì)我們的布局進(jìn)行測(cè)量,也就是重寫(xiě)onMeasure方法。

在該方法中,我們需要對(duì)我們的布局進(jìn)行測(cè)量,并且將測(cè)量好的寬高傳入setMeasuredDimension方法,完成測(cè)量。

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight)

之前我們說(shuō)過(guò),onMeasure方法會(huì)傳進(jìn)來(lái)兩個(gè)參數(shù),widthMeasureSpec和heightMeasureSpec。

里面包含了父View根據(jù)當(dāng)前View的LayoutParams和父View的測(cè)量規(guī)格進(jìn)行計(jì)算,得出的對(duì)當(dāng)前View期望的測(cè)量模式和測(cè)量大小:

當(dāng)測(cè)量模式為MeasureSpec.EXACTLY

也就是當(dāng)寬或者高為確定值時(shí),那么當(dāng)前布局View的寬高也就是設(shè)定為父View給我們?cè)O(shè)置好的測(cè)量大小即可。比如寬為400dp,那么我們無(wú)需重新測(cè)量直接調(diào)用setMeasuredDimension傳入這個(gè)固定值即可。

當(dāng)測(cè)量模式為MeasureSpec.AT_MOST 或者 UNSPECIFIED:

這時(shí)候,說(shuō)明父View對(duì)當(dāng)前View的要求不固定,是可以為任意大小或者不超過(guò)最大值的情況,比如設(shè)置這個(gè)VerticalLayout的高度為wrap_content。那么我們就必須重新進(jìn)行高度測(cè)量了,因?yàn)橹挥形覀冊(cè)O(shè)計(jì)者知道這個(gè)自適應(yīng)高度需要怎么計(jì)算。具體就是VerticalLayout是一個(gè)垂直線(xiàn)性布局,所以高度很自然就是所有子View的高度之和。

至此,onMeasure方法的邏輯也基本摸清了:

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)//獲取寬高的測(cè)量模式和測(cè)量大小val widthMode = MeasureSpec.getMode(widthMeasureSpec)val heightMode = MeasureSpec.getMode(heightMeasureSpec)val sizeWidth = MeasureSpec.getSize(widthMeasureSpec)val sizeHeight = MeasureSpec.getSize(heightMeasureSpec) var mHeight = 0var mWidth = 0 //遍歷子View,獲取總高度f(wàn)or (i in 0 until childCount) { val childView = getChildAt(i) //測(cè)量子View的寬和高 measureChild(childView, widthMeasureSpec, heightMeasureSpec) val lp = childView.layoutParams as MarginLayoutParams val childWidth = childView.measuredWidth + lp.leftMargin + lp.rightMargin val childHeight = childView.measuredHeight + lp.topMargin + lp.bottomMargin //計(jì)算得出最大寬度 mWidth = Math.max(mWidth, childWidth) //累計(jì)計(jì)算高度 mHeight += childHeight} //設(shè)置寬高setMeasuredDimension( if (widthMode == MeasureSpec.EXACTLY) sizeWidth else mWidth, if (heightMode == MeasureSpec.EXACTLY) sizeHeight else mHeight) }

主要的邏輯就是遍歷子View,得出VerticalLayout的實(shí)際寬高:

最終ViewGroup的高 = 所有子View的 (高 + margin值) 最終ViewGroup的寬 = 最大子View的 (寬 + margin值)

最后調(diào)用setMeasuredDimension 根據(jù)測(cè)量模式 傳入寬高。

重寫(xiě)布局方法onLayout

上文說(shuō)過(guò),作為一個(gè)ViewGroup,必須重寫(xiě)onLayout方法,來(lái)保證子View的正常布局?jǐn)[放。

垂直線(xiàn)性布局VerticalLayout亦是如此,那么在這個(gè)布局中onLayout方法的關(guān)鍵邏輯又是什么呢?

還是那句話(huà),確定位置,也就是確定左、上、右、下四個(gè)參數(shù)值,而在VerticalLayout中,最關(guān)鍵的參數(shù)就是這個(gè)上,也就是top值。

每個(gè)View的top值必須是上一個(gè)View的bottom值,也就是接著上一個(gè)View進(jìn)行擺放,這樣才會(huì)是垂直線(xiàn)性的效果,所以我們需要做的就是動(dòng)態(tài)計(jì)算每個(gè)View的top值,其實(shí)也就是不斷累加View的高度,作為下一個(gè)View的top值。

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {var childWidth = 0var childHeight = 0var childTop = 0var lp: MarginLayoutParams //遍歷子View,布局每個(gè)子Viewfor (i in 0 until childCount) { val childView = getChildAt(i) childHeight = childView.measuredHeight childWidth = childView.measuredWidth lp = childView.layoutParams as MarginLayoutParams //累計(jì)計(jì)算top值 childTop += lp.topMargin //布局子View childView.layout(lp.leftMargin,childTop,lp.leftMargin + childWidth,childTop + childHeight ); childTop += childHeight + lp.bottomMargin} }

邏輯還是挺簡(jiǎn)單的,

left是固定的子View的leftMargin。 top是累加計(jì)算的子View的高度 + Margin值。 right是left + 子View的寬度。 bottom是top + 子View的高度。

最后調(diào)用子View的layout方法,對(duì)每個(gè)子View進(jìn)行布局。

大功告成,最后看看我們這個(gè)自定義垂直線(xiàn)性布局的效果吧~

四、效果展示

<com.panda.studynote3.VerticalLayoutandroid:layout_width='wrap_content'android:layout_height='wrap_content'> <TextView android:layout_width='100dp' android:layout_height='100dp' android:text='啦啦啦' android:textSize='20sp' android:textColor='@color/white' android:background='@color/design_default_color_primary' /> <TextView android:layout_width='300dp' android:layout_height='200dp' android:layout_marginTop='20dp' android:background='@color/cardview_dark_background' android:textSize='20sp' android:textColor='@color/white' android:text='你好啊' /> <TextView android:layout_width='140dp' android:layout_height='100dp' android:text='嘻嘻' android:layout_marginLeft='10dp' android:layout_marginTop='10dp' android:textSize='20sp' android:gravity='center' android:textColor='@color/black' android:background='@color/teal_200' /> </com.panda.studynote3.VerticalLayout>

JavaSwing基礎(chǔ)之Layout布局相關(guān)知識(shí)詳解

到此這篇關(guān)于Java基礎(chǔ)之Layout布局相關(guān)知識(shí)詳解的文章就介紹到這了,更多相關(guān)Java Layout布局內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Java
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
欧洲一区二区三区精品| 特黄毛片在线观看| 亚洲午夜黄色| 婷婷久久一区| 丝袜a∨在线一区二区三区不卡| 一区久久精品| 亚洲精品黄色| 国产精品最新自拍| 91日韩免费| 久久高清免费| 一区二区精彩视频| 国产麻豆一区| 久久精品国产久精国产爱| 美女av在线免费看| 国产色综合网| 日韩精品一区二区三区中文在线| 国产亚洲高清一区| 国产成人精品亚洲日本在线观看| 在线 亚洲欧美在线综合一区| 日韩欧乱色一区二区三区在线| 久久午夜影院| 亚洲欧美久久| 久久亚洲精品中文字幕| 九九综合九九| 97久久中文字幕| 日韩一区二区中文| 亚洲精品观看| 国产伦一区二区三区| 久久久久国产| 日本视频在线一区| 国产91一区| 国产欧美一区二区三区米奇| 午夜欧美巨大性欧美巨大| 影音先锋久久精品| 日韩综合精品| 欧美午夜网站| 欧美美女一区| 国产精品主播| 欧美中文日韩| 日韩激情一区| 国产精品资源| 首页亚洲欧美制服丝腿| 美女精品视频在线| 亚洲另类黄色| 欧美freesex黑人又粗又大| 蜜臀久久99精品久久久久久9| 久久伊人久久| 亚洲精品大全| 免费欧美一区| 久久97久久97精品免视看秋霞| 久久国产成人| 国产高潮在线| 国产精品网址| 三级亚洲高清视频| 群体交乱之放荡娇妻一区二区| 国产精品视频3p| 中文字幕一区二区av| 久久久久中文| 久久精品一区| 国产精品久久| 婷婷亚洲成人| 红桃视频亚洲| 成人羞羞视频播放网站| 国产第一亚洲| 久久99偷拍| 欧美日韩亚洲国产精品| 日韩精品一级中文字幕精品视频免费观看 | 欧美aⅴ一区二区三区视频| 久久亚洲欧洲| 免费一区二区视频| 精品国产鲁一鲁****| 亚洲精品乱码日韩| 玖玖玖国产精品| se01亚洲视频| 国产一区二区三区不卡av| 国产乱论精品| 亚洲精品影视| 日韩一区欧美二区| 亚洲黄色在线| 婷婷综合亚洲| 91精品一区二区三区综合在线爱| 国产成人1区| 精品国产aⅴ| 麻豆久久一区| 久久麻豆视频| 狠狠久久伊人中文字幕| 久久久精品区| 国产一区二区三区国产精品| 国产精品一国产精品k频道56| 日本精品一区二区三区在线观看视频| 蜜乳av另类精品一区二区| 91精品成人| 亚洲免费激情| 亚洲综合专区| 日本精品一区二区三区在线观看视频| 综合色一区二区| 亚洲精品美女| 国产精品片aa在线观看| 欧美精品aa| 九九九精品视频| 日韩深夜视频| 米奇777超碰欧美日韩亚洲| 国产亚洲综合精品| 久久高清免费观看| 亚洲精品乱码久久久久久蜜桃麻豆| 亚洲精品高潮| 久久不见久久见中文字幕免费| 国产一区二区三区天码| 日韩欧美一区二区三区免费观看| 激情综合网址| 人人爽香蕉精品| 国产日韩欧美在线播放不卡| 精品九九在线| 欧美亚洲国产激情| 亚洲另类黄色| 国产精品久久久久久模特 | 久久蜜桃精品| 国产精品毛片| 91精品在线免费视频| 老司机精品视频网| 久久国产亚洲| 免费观看日韩电影| 国产高清精品二区| 久久国产免费| 综合国产视频| 成人日韩av| 国产亚洲激情| 国产精品一二| 日本少妇一区| 亚洲一区二区免费在线观看| 国产欧美精品久久| 久久中文亚洲字幕| 欧美天堂一区二区| 日韩不卡视频在线观看| 一区二区三区四区日韩| 欧美国产日韩电影| 宅男在线一区| 久久国产精品色av免费看| 日韩欧美少妇| 日韩精品免费视频一区二区三区 | 欧美日韩xxxx| 日精品一区二区三区| 欧美一级全黄| 精品国产乱码久久久久久樱花| 五月婷婷亚洲| 国产精品**亚洲精品| 欧美 日韩 国产一区二区在线视频| 亚洲精品日韩久久| 日韩免费高清| 婷婷综合国产| 啪啪国产精品| 日韩av不卡一区二区| 色综合www| 久久国产人妖系列| 欧美aa一级| 国产日韩三级| 国产精品日本| 粉嫩av一区二区三区四区五区 | 日本伊人久久| 久久九九国产| 国产精品久久777777毛茸茸| 激情欧美一区| 精品日产乱码久久久久久仙踪林| 西西人体一区二区| 亚洲风情在线资源| 欧美亚洲一级| 日韩中文欧美在线| 久久国产中文字幕| 蜜桃久久久久| 91精品一区| 日韩专区一卡二卡| 欧美日韩一二三四| 久久亚洲国产精品尤物| 日韩精品视频网站| 日韩视频久久| 日韩在线中文| 欧美a一区二区| 中文字幕日本一区二区| 蜜臀久久99精品久久一区二区| 97精品中文字幕| 国产精品99久久免费观看| 亚洲天堂av资源在线观看| 精品日韩毛片| 天堂日韩电影| 久草免费在线视频| 精品国产日韩欧美精品国产欧美日韩一区二区三区 | 九九精品调教| 国产福利91精品一区二区| 久久激五月天综合精品| 亚洲精品影视| 亚洲+小说+欧美+激情+另类| 只有精品亚洲| 综合在线一区| 亚洲精品自拍| 日本成人在线不卡视频| 日本成人在线视频网站| 日韩视频一二区| 四虎精品一区二区免费| 亚洲精品婷婷| 日韩av一区二区三区四区|