11

我希望能够用动画扩展 ListView 中的行。因此我需要知道正在扩展的视图的高度。我在我的getView()方法中使用它ArrayAdapter

mDetailsView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        mDetailsView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

        onClickListener.setHeight(mDetailsView.getHeight());
        mDetailsView.setVisibility(View.GONE);
    }
});

这适用于开始时在屏幕上可见的行,但是当我向下滚动时,onGlobalLayout不会为最初不可见的行调用该方法。

如何获得这些行的高度?

4

4 回答 4

14

的实现可能ListView不会执行整个布局,因此ViewTreeObserver永远不会真正看到正在进行的布局。

除非有一些我不知道的特定手机壳,否则您可以使用 Views 中的post方法在视图中执行 runnable 。

mDetailsView.post(new Runnable() {
  @Override
  public void run() {
    onClickListener.setHeight(mDetailsView.getHeight());
    mDetailsView.setVisibility(View.GONE);
  }
});

编辑:

我不知道整个getView()方法是如何布置的。如果我不得不猜测,问题是ListView根本没有请求布局。相反,它为每个视图自己做工作以加快速度。您可以尝试的是:

public void getView(int position, View convertView, ViewGroup parent) {

  /* 
   * set your view up
   */

  mDetailsView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        mDetailsView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

        onClickListener.setHeight(mDetailsView.getHeight());
        mDetailsView.setVisibility(View.GONE);
       }
   });

   notifyDataSetInvalidated(); // Notify the ListView() and any other listeners that your views are invalid.
   return view;
}

新编辑:使用notifyDataSetInvalidated()in 通常是个坏主意,尤其是在getView().

要预先测量布局,您可以使用它的布局参数,或者如果它们不存在则给它新的参数。

    LayoutParams params = newView.getLayoutParams();
    if (params == null) {
        params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }
    final int widthSpec = MeasureSpec.makeMeasureSpec(parent.getWidth(), MeasureSpec.UNSPECIFIED);
    final int heightSpec = MeasureSpec.makeMeasureSpec(parent.getHeight(), MeasureSpec.UNSPECIFIED);
    newView.measure(widthSpec, heightSpec);
于 2013-01-14T19:37:29.630 回答
8

在 ListView 或 RecyclerView 而不是使用OnGlobalLayoutListener我总是使用OnPreDrawListener. 在开始时也会为不可见的行触发此回调。来自官方文档:

此时,树中的所有视图都已被测量并给出了一个框架。

于 2016-07-27T22:19:22.853 回答
1

好的,所以看起来我遇到了类似的问题。

出于某种原因,如果 ListView 在中间丢失了 convertView ,那么当重新膨胀视图时,如果设置了它,它就不会调用它的全局布局侦听器。

这是我想出的解决方法:

public class MyViewThatIsInList extends View {
  public MyViewThatIsInList (Context context) {
      super(context);
      ensureInited();
  }

  public MyViewThatIsInList (Context context, AttributeSet attrs) {
      this(context, attrs, 0);
  }

  public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);

      TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0);
      //...
      ensureInited();
  }

  boolean isViewInited = false;
  private void init() {
      getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
          @Override
          public void onGlobalLayout() {
              //my custom helper method
              Utils.safeRemoveLayoutListener(getViewTreeObserver(), this);
              initLogic();
          }
      });
  }

  private void initLogic() {
    //...
    isViewInited = true;
  }

   private void ensureInited() {
      init();
      postDelayed(new Runnable() {
          @Override
          public void run() {
              if (!isViewInited) {
                  initLogic();
              }
          }
      }, 500);
  }

}
于 2014-07-10T19:32:35.973 回答
1

在 ListView 或 RecyclerView 中,我们总是使用 OnPreDrawListener 而不是使用 OnGlobalLayoutListener。在开始时也会为不可见的行触发此回调。来自官方文档:

private void makeTextViewResizable(final TextView tv, final int maxLine, final String expandText, final boolean viewMore) {

    try {
        if (tv.getTag() == null) {
            tv.setTag(tv.getText());
        }
        //OnGlobalLayoutListener
        ViewTreeObserver vto = tv.getViewTreeObserver();
        vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

            @Override
            public boolean onPreDraw() {

                    ViewTreeObserver obs = tv.getViewTreeObserver();
                   // obs.removeGlobalOnLayoutListener((ViewTreeObserver.OnGlobalLayoutListener) mActivity);
                    obs.removeOnPreDrawListener(this);
                    if (maxLine == 0) {
                        int lineEndIndex = tv.getLayout().getLineEnd(0);
                        String text = tv.getText().subSequence(0, lineEndIndex - expandText.length() + 1) + " " + expandText;
                        tv.setText(text);
                        tv.setMovementMethod(LinkMovementMethod.getInstance());
                        tv.setText(
                                addClickablePartTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText,
                                        viewMore), TextView.BufferType.SPANNABLE);
                    } else if (maxLine > 0 && tv.getLineCount() >= maxLine) {
                        int lineEndIndex = tv.getLayout().getLineEnd(maxLine - 1);
                        String text = tv.getText().subSequence(0, lineEndIndex - expandText.length() + 1) + " " + expandText;
                        tv.setText(text);
                        tv.setMovementMethod(LinkMovementMethod.getInstance());
                        tv.setText(
                                addClickablePartTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText,
                                        viewMore), TextView.BufferType.SPANNABLE);
                    } else {
                        int lineEndIndex = tv.getLayout().getLineEnd(tv.getLayout().getLineCount() - 1);
                        String text = tv.getText().subSequence(0, lineEndIndex) + " " + expandText;
                        tv.setText(text);
                        tv.setMovementMethod(LinkMovementMethod.getInstance());
                        tv.setText(
                                addClickablePartTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText,
                                        viewMore), TextView.BufferType.SPANNABLE);
                    }


                return true;
            }


        });
    } catch (Exception e) {
        e.printStackTrace();
    }

}
于 2016-09-27T09:41:39.473 回答