web-dev-qa-db-ja.com

Android:ビューを描画する前に高さを取得します

アニメーションの場合、ビューからの高さを知る必要があります。問題は、ビューが描画されない限り、getHeight()メソッドが常に0を返すことです。だから、それを描画せずに高さを取得する方法はありますか?

この場合、ビューはLinearLayoutです。

編集: https://github.com/Udinic/SmallExamples/blob/master/ExpandAnimationExample/src/com/udinic/expand_animation_example/ExpandAnimation.Java からエキスパンドアニメーションを適応させようとしています。

それを使用して、リストアイテムの情報をさらに拡張します。 xmlを介して同じ効果を達成することができませんでした。現時点では、アニメーションを描画する前にレイアウトサイズがわかっている場合にのみ機能します。

46
anonymous

高さを取得したいが、表示される前にビューを非表示にしたいようです。

ビューの可視性を可視または非可視に設定して開始します(高さが作成されるように)。以下に示すように、コード内で非表示/非表示に変更することを心配しないでください。

private int mHeight = 0;
private View mView;

class...

// onCreate or onResume or onStart ...
mView = findViewByID(R.id.someID);
mView.getViewTreeObserver().addOnGlobalLayoutListener( 
    new OnGlobalLayoutListener(){

        @Override
        public void onGlobalLayout() {
            // gets called after layout has been done but before display
            // so we can get the height then hide the view


            mHeight = mView.getHeight();  // Ahaha!  Gotcha

            mView.getViewTreeObserver().removeGlobalOnLayoutListener( this );
            mView.setVisibility( View.GONE );
        }

});
124
Jim Baca

同様の状況で同様の問題が発生しました。

アニメーションの対象となるviewの高さを必要とするアニメーションを作成する必要がありました。 viewであるLinearLayoutは、TextView型の子ビューになる場合があります。 TextViewは複数行であり、実際に必要な行数は異なります。

私が何をしたとしても、TextViewが1行だけであるかのように、ビューの測定された高さを取得しました。テキストがたまたま1行の長さになるたびにこれがうまく機能したのは不思議ではありませんが、テキストが行よりも長い場合は失敗しました。

私はこの答えを考えました: https://stackoverflow.com/a/6157820/854396 しかし、埋め込みTextViewにアクセスできないので、それは私にとってあまりうまく機能しませんでしたここから直接。 (ただし、子ビューのツリーを反復処理することもできました。)

今のところ動作する私のコードを見てください:

viewは、アニメーション化されるビューです。これはLinearLayoutです(最終的な解決策は、ここでもう少し型を保存します)thisは、viewを含み、LinearLayoutから継承するカスタムビューです。

   private void expandView( final View view ) {

      view.setVisibility(View.VISIBLE);

      LayoutParams parms = (LayoutParams) view.getLayoutParams();
      final int width = this.getWidth() - parms.leftMargin - parms.rightMargin;

      view.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
              MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));

      final int targetHeight = view.getMeasuredHeight();

      view.getLayoutParams().height = 0;

      Animation anim = new Animation() {
         @Override
         protected void applyTransformation( float interpolatedTime, Transformation trans ) {
            view.getLayoutParams().height =  (int) (targetHeight * interpolatedTime);
            view.requestLayout();
         }

         @Override
         public boolean willChangeBounds() {
            return true;
         }
      };

      anim.setDuration( ANIMATION_DURATION );
      view.startAnimation( anim );
   }

これはほぼそれでしたが、私は別の間違いを犯しました。ビュー階層内には、LinearLayoutのサブクラスである2つのカスタムビューが含まれ、それらのxmlはxmlルートタグとしてmergeタグにマージされます。これらのmergeタグのいずれかで、Android:orientation属性をverticalに。このマージされたViewGroupの中にはただ1つの子ViewGroupがあり、そのため実際には画面上で間違った方向を見ることができなかったため、レイアウト自体にはあまり気にしませんでした。しかし、そこにあり、このレイアウト測定ロジックを少し壊しました。

上記に加えて、ビュー階層内のLinearLayoutsおよびサブクラスに関連付けられたすべてのパディングを取り除くことが必要になる場合があります。同じように見えるように別のレイアウトをラップする必要がある場合でも、マージンで置き換えます。

21
Hermann Klecker

技術的には、ビューでmeasureメソッドを呼び出し、getMeasureHeightを介してその高さを取得できます。詳細はこちらをご覧ください: https://developer.Android.com/guide/topics/ui/how-Android-draws.html 。ただし、MeasureSpecを指定する必要があります。

しかし実際には、ビューのサイズはその親レイアウトの影響を受けるため、実際に描画されるときとは異なるサイズになる場合があります。

また、RELATIVE_TO_SELFアニメーションの値。

12
Fixpoint
static void getMeasurments(View v) {

    v.measure(View.MeasureSpec.makeMeasureSpec(PARENT_VIEW.getWidth(), 
      View.MeasureSpec.EXACTLY),
         View.MeasureSpec.makeMeasureSpec(0, 
      View.MeasureSpec.UNSPECIFIED));

    final int targetHeight = v.getMeasuredHeight();
    final int targetWidth = v.getMesauredWidth();
}
4
Anubhav

更新された投稿については、次のことが役立ちます。 Animation#initialize method。コンストラクタの代わりに初期化を配置するだけで、必要なサイズがすべて揃います。

0
Fixpoint

親がそのサイズを決定しない場合は、自分で測定します。

常にあなたのためにそれを行うためのビュー上のkotlin拡張があります:

fun View.getMeasurments(): Pair<Int, Int> {
    measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
    val width = measuredWidth
    val height = measuredHeight
    return width to height
}
0
j2emanue