2016-04-12 3 views
0

Я расширяю AppBarLayout, чтобы создать свою собственную версию. Моя цель - установить некоторые LayoutParameters во время выполнения, например. высота AppBar.Настройка пользовательских ViewGroup/композитных представлений 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); 
    } 
} 

Есть ли способ, чтобы установить LayoutParameters внутри конструктора обычая ViewGroup/композитный View?


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

Ну, NullPointerException вы получаете связано с LayoutParams будучи нулевым, поскольку Посмотреть еще не выложена системы. Это дает вам два варианта: вы можете либо отложить настройку параметра до тех пор, пока не будет отображен вид, либо использовать внутреннюю onMeasure View (аналогично тому, как вы используете), чтобы рассказать, как ее выложить.

Первый может быть достигнуто с OnGlobalLayoutListener из ViewTreeOberserver:

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 проделал довольно хорошую работу, объяснив это. Просто подумал, что может указать вам в правильном направлении.

 Смежные вопросы

  • Нет связанных вопросов^_^