我希望能够通过动画扩展ListView中的行。因此,我需要知道正在扩展的视图的高度。我在getView()
的{{1}}方法中使用了这个:
ArrayAdapter
这适用于开始时在屏幕上可见的行,但是当我向下滚动时,不会为最初不可见的行调用mDetailsView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mDetailsView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
onClickListener.setHeight(mDetailsView.getHeight());
mDetailsView.setVisibility(View.GONE);
}
});
方法。
如何获得这些行的高度?
答案 0 :(得分:13)
ListView
的实现可能不会执行整个布局,因此ViewTreeObserver
实际上看不到正在进行的布局。
除非我不知道某些特定的手机外壳,否则您可以使用视图中的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()
通常是一个坏主意,特别是在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);
答案 1 :(得分:6)
在ListView或RecyclerView中,而不是使用OnGlobalLayoutListener
我总是使用OnPreDrawListener
。对于启动时的非可见行,也会触发此回调。从官方文档:
此时,树中的所有视图都已经过测量并给出了一个框架。
答案 2 :(得分: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);
}
}
答案 3 :(得分: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();
}
}