我正在扩展AppBarLayout以制作我自己的版本。我的目标是在运行时设置一些LayoutParameters,例如。 AppBar的高度。
我得到一个NPE,如果我尝试设置任何Paramteres,我想因为尚未创建和设置LayoutParameters。
public MyAppBar(Context context, AttributeSet attrs) {
super(context, attrs);
...
LayoutInflater.from(context).inflate(R.layout.layout_my_app_bar, this, true);
ViewGroup.LayoutParams params = this.getLayoutParams();
params.height = calculateExpandedHeight(selectedAspectRatio);
this.setLayoutParams(params);
...
}
我目前的解决方法是在LayoutParams
内设置onMeasure
:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(!hasSetHeight) {
ViewGroup.LayoutParams params = this.getLayoutParams();
params.height = mExpandedHeight;
this.setLayoutParams(params);
}
}
有没有办法在自定义ViewGroup /复合视图的构造函数中设置LayoutParameters?
layout_my_app_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/tools">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</merge>
答案 0 :(得分:0)
嗯,您获得的NullPointerException与LayoutParams为空相关,因为系统尚未布置View。这为您提供了两个选项:您可以延迟参数调整直到View布局,或者使用View的内部onMeasure(类似于您的使用方式)来告诉它如何布局。
前者可以使用ViewTreeOberserver中的OnGlobalLayoutListener实现:
public MyAppBar(Context context, AttributeSet attrs) {
super(context, attrs);
...
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
ViewGroup.LayoutParams params = this.getLayoutParams();
// Set the params here
removeOnGlobalLayoutListener(MyAppBar.this, this); // Remove the listener
}
});
requestLayout();
}
@SuppressLint("NewApi")
public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener) {
if(Build.VERSION.SDK_INT < 16)
v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
else v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
后者可能(略微)更好,因为你只应用看似宽高比的东西,就是使用onMeasure方法并将转换应用到那里的widthMeasureSpec。 e.g。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int adjustedHeight = MeasureSpec.getSize(widthMeasureSpec) / selectedAspectRatio
super.onMeasure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(adjustedHeight, MeasureSpec.getMode(MeasureSpec.EXACTLY)));
}
请记住,onMeasure并没有真正考虑其他MeasureSpec的可能性,而且我做了一个巨大的假设,你总是知道宽度,并希望高度根据它自行调整。如果你想要更有活力并考虑其他案例,easy View measuring做了很好的解释。只是想到这可能会指出你正确的方向。