展会信息港展会大全

Android (单帧布局)FrameLayout
来源:互联网   发布日期:2015-10-13 14:53:22   浏览:1231次  

导读:感觉FrameLayout很神秘,是因为用到它的地方少,一直觉得它鸡肋,原来是自己无知。最近需要实现一些layer的效果,就用到了它。它的用法很简单,这里就不多说了,这里就说说它的原理吧。FrameLayout类里面没有什么......

感觉FrameLayout很神秘,是因为用到它的地方少,一直觉得它鸡肋,原来是自己无知。最近需要实现一些layer的效果,就用到了它。它的用法很简单,这里就不多说了,这里就说说它的原理吧。

FrameLayout类里面没有什么东西,主要说的还是它的自身的布局参数FrameLayout.LayoutParams,布局参数类继承 MarginLayoutParams。看名词就知道,就是控制view的外边距的,FrameLayout.LayoutParams本身自己定义的参 数只有一个gravity。

好了,既然有了布局参数,那就会有空间的一些属性吧。首先FrameLayout也是一个View,所以他必然有Padding(view的内边距)相关属性。这里我们重点关注它的onMeasure与onLayout:

onMeasure意思就是计算出该ViewGroup的布局大小及孩子View的布局大小

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int count = getChildCount();

final boolean measureMatchParentChildren =

MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||

MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;

mMatchParentChildren.clear();

int maxHeight = 0;

int maxWidth = 0;

int childState = 0;

for (int i = 0; i < count; i++) {

final View child = getChildAt(i);

if (mMeasureAllChildren || child.getVisibility() != GONE) {

measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);

final LayoutParams lp = (LayoutParams) child.getLayoutParams();

maxWidth = Math.max(maxWidth,

child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);

maxHeight = Math.max(maxHeight,

child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);

childState = combineMeasuredStates(childState, child.getMeasuredState());

if (measureMatchParentChildren) {

if (lp.width == LayoutParams.MATCH_PARENT ||

lp.height == LayoutParams.MATCH_PARENT) {

mMatchParentChildren.add(child);

}

}

}

}

// Account for padding too

maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();

maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();

// Check against our minimum height and width

maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());

maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());

// Check against our foreground's minimum height and width

final Drawable drawable = getForeground();

if (drawable != null) {

maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());

maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());

}

setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),

resolveSizeAndState(maxHeight, heightMeasureSpec,

childState << MEASURED_HEIGHT_STATE_SHIFT));

count = mMatchParentChildren.size();

if (count > 1) {

for (int i = 0; i < count; i++) {

final View child = mMatchParentChildren.get(i);

final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

int childWidthMeasureSpec;

int childHeightMeasureSpec;

if (lp.width == LayoutParams.MATCH_PARENT) {

childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -

getPaddingLeftWithForeground() - getPaddingRightWithForeground() -

lp.leftMargin - lp.rightMargin,

MeasureSpec.EXACTLY);

} else {

childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,

getPaddingLeftWithForeground() + getPaddingRightWithForeground() +

lp.leftMargin + lp.rightMargin,

lp.width);

}

if (lp.height == LayoutParams.MATCH_PARENT) {

childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -

getPaddingTopWithForeground() - getPaddingBottomWithForeground() -

lp.topMargin - lp.bottomMargin,

MeasureSpec.EXACTLY);

} else {

childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,

getPaddingTopWithForeground() + getPaddingBottomWithForeground() +

lp.topMargin + lp.bottomMargin,

lp.height);

}

child.measure(childWidthMeasureSpec, childHeightMeasureSpec);

}

}

}

简单的说父容器的width就是所有孩子View的width取最大值加View外边距和它的内边距:child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin+getPaddingLeftWithForeground() + getPaddingRightWithForeground();如果ViewGroup有图片,还有跟图片比较取较大值,容器的height也是同样 的道理。FrameLayout孩子View的布局大小跟普通View大小确定是一样的。

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

final int count = getChildCount();

final int parentLeft = getPaddingLeftWithForeground();

final int parentRight = right - left - getPaddingRightWithForeground();

final int parentTop = getPaddingTopWithForeground();

final int parentBottom = bottom - top - getPaddingBottomWithForeground();

mForegroundBoundsChanged = true;

for (int i = 0; i < count; i++) {

final View child = getChildAt(i);

if (child.getVisibility() != GONE) {

final LayoutParams lp = (LayoutParams) child.getLayoutParams();

final int width = child.getMeasuredWidth();

final int height = child.getMeasuredHeight();

int childLeft;

int childTop;

int gravity = lp.gravity;

if (gravity == -1) {

gravity = DEFAULT_CHILD_GRAVITY;

}

final int layoutDirection = getResolvedLayoutDirection();

final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);

final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;

switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {

case Gravity.LEFT:

childLeft = parentLeft + lp.leftMargin;

break;

case Gravity.CENTER_HORIZONTAL:

childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +

lp.leftMargin - lp.rightMargin;

break;

case Gravity.RIGHT:

childLeft = parentRight - width - lp.rightMargin;

break;

default:

childLeft = parentLeft + lp.leftMargin;

}

switch (verticalGravity) {

case Gravity.TOP:

childTop = parentTop + lp.topMargin;

break;

case Gravity.CENTER_VERTICAL:

childTop = parentTop + (parentBottom - parentTop - height) / 2 +

lp.topMargin - lp.bottomMargin;

break;

case Gravity.BOTTOM:

childTop = parentBottom - height - lp.bottomMargin;

break;

default:

childTop = parentTop + lp.topMargin;

}

child.layout(childLeft, childTop, childLeft + width, childTop + height);

}

}

}

从代码中可以看出,孩子View左上角坐标的X值就是ViewGroup的左内边距加上view的外边距,Y值同理。

哎,怎么感觉自己写着写着,还把问题说复杂了点,感觉还是看代码能明白。

还有,我在2.2版本的代码上,gravity与margin属性必须同时设置,margin才能发挥作用,如果只有margin属性而没有设置gravity,就没有效果。如果有谁知道,欢迎指教哈。

在上一篇中说了下android里drag and drop 一个View,当时那个imageView放在一个LinearLayout里面,事实上放在FrameLayout同样适用,因为他们的布局参数都继承 MarginLayoutParams类,所以通过margin控制他们的布局位置同样在FrameLayout使用。事实上 GridLayout,LinearLayout,RelativeLayout,FrameLayout的布局参数都是继承 MarginLayoutParams的。

赞助本站

人工智能实验室

相关热词: 单帧布局 FrameLayout

AiLab云推荐
推荐内容
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港