在其构造函数中设置自定义 ViewGroup/复合视图 LayoutParameters
Setting custom ViewGroup/ composite View LayoutParameters inside its' constructor
我正在扩展 AppBarLayout 以制作我自己的版本。我的目标是在运行时设置一些 LayoutParameters,例如。 AppBar 高度。
我得到一个 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);
...
}
我目前的解决方法是在 onMeasure
中设置 LayoutParams
:
@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>
嗯,您得到的NullPointerException 与LayoutParams 为null 有关,因为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。例如
@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 做了很好的解释。只是认为这可能会为您指明正确的方向。
我正在扩展 AppBarLayout 以制作我自己的版本。我的目标是在运行时设置一些 LayoutParameters,例如。 AppBar 高度。
我得到一个 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);
...
}
我目前的解决方法是在 onMeasure
中设置 LayoutParams
:
@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>
嗯,您得到的NullPointerException 与LayoutParams 为null 有关,因为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。例如
@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 做了很好的解释。只是认为这可能会为您指明正确的方向。