本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!
为什么ViewGroup的addView方法和PopupWindow的show方法都不支持设置width和height?
2011年开始做安卓开发,今年是第9个年头。回首这些年,从开发做起,做过组长,也做过架构,主要时间还是在做开发,也就是跟业务打交道。第5个年头,没能再上一个台阶,受2016年的“互联网企业倒闭潮流”的影响,先后在2家公司待了不长时间,来到现在的公司,时间紧-一周一个版本、负担重-几年的代码积累、人员新-小组司龄不超过半年、业务多-1(原业务)+4(新业务)模块开发,过去的1年多是在赶进度,往往是在持续做业务,主要是直播,很少有机会去整理框架或者Sdk,只能做到核心Api封装,遇到不少未曾重视过的UI细节。今天来讲一讲常用的ScrollView+LinearLayout和PopupWindow问题,用于记录,以防后面再发生这种小问题。
通常情况下,遇到item不多且会变动的功能,往往考虑使用ScrollView+LinearLayout的方案,ListView之类的控件过于庞大且复用性不强,LinearLayout的Orientation有横向和纵向两个添加子View的方式,比较适用这种场景。以往都是针对子View设置padding来保障LinearLayout的宽度和高度;这次想通过设置子View的宽高,让子View进行自适应,可是实验失败:
实验方案:linearLayout.addView(view),未使用LayoutParams。
翻看源码:
public void addView(View child, int index) {
if (child == null) {
throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
}
LayoutParams params = child.getLayoutParams();
if (params == null) {
params = generateDefaultLayoutParams();
if (params == null) {
throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
}
}
addView(child, index, params);
}
确认如果不添加LayoutParams,则默认生成一个(通过LayoutInflate生成的View无LayoutParams)
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
可以得知width和height设置失效。但padding设置有效,因为它是从AttributSet时取的值。
因此:方案是设置LinearLayout和子View的padding即可。
接下来是PopupWindow的宽高设置问题,同理,见源码
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
if (isShowing() || !hasContentView()) {
return;
}
TransitionManager.endTransitions(mDecorView);
attachToAnchor(anchor, xoff, yoff, gravity);
mIsShowing = true;
mIsDropdown = true;
final WindowManager.LayoutParams p =
createPopupLayoutParams(anchor.getApplicationWindowToken());
preparePopup(p);
final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
p.width, p.height, gravity, mAllowScrollingAnchorParent);
updateAboveAnchor(aboveAnchor);
p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;
invokePopup(p);
}
protected final WindowManager.LayoutParams createPopupLayoutParams(IBinder token) {
final WindowManager.LayoutParams p = new WindowManager.LayoutParams();
// These gravity settings put the view at the top left corner of the
// screen. The view is then positioned to the appropriate location by
// setting the x and y offsets to match the anchor's bottom-left
// corner.
p.gravity = computeGravity();
p.flags = computeFlags(p.flags);
p.type = mWindowLayoutType;
p.token = token;
p.softInputMode = mSoftInputMode;
p.windowAnimations = computeAnimationResource();
if (mBackground != null) {
p.format = mBackground.getOpacity();
} else {
p.format = PixelFormat.TRANSLUCENT;
}
if (mHeightMode < 0) {
p.height = mLastHeight = mHeightMode;
} else {
p.height = mLastHeight = mHeight;
}
if (mWidthMode < 0) {
p.width = mLastWidth = mWidthMode;
} else {
p.width = mLastWidth = mWidth;
}
p.privateFlags = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH
| PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
// Used for debugging.
p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
return p;
}
又是LayoutParams的设置问题。
解决方案:给整体布局设置宽高以及padding之后,再嵌套一个布局,即可预防LayoutParams被重置的问题。