0

我正在扩展 AppBarLayout 以制作我自己的版本。我的目标是在运行时设置一些 LayoutParameters,例如。应用栏高度。

我得到一个 NPE,如果我尝试设置任何参数,我猜是因为尚未创建和设置 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>
4

1 回答 1

0

好吧,您得到的 NullPointerException 与 LayoutParams 为空有关,因为系统尚未布置视图。这为您提供了两种选择:您可以延迟参数调整,直到视图布局完毕,或者使用视图的内部 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 。例如

@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 的可能性,我做出了一个巨大的假设,即您将始终知道宽度并希望基于此调整高度。如果您想更加动态并考虑其他情况,那么简单的视图测量可以很好地解释它。只是认为这可能会为您指明正确的方向。

于 2016-04-12T16:56:07.230 回答