我有一个android布局,其中有一个带有许多元素的scrollView。在scrollView的底部,我有一个listView,然后由适配器填充。
我遇到的问题是,android是排除listView从scrollView作为scrollView已经有一个可滚动的功能。我希望listView和内容一样长,并且主滚动视图是可滚动的。
我怎样才能实现这种行为呢?
这是我的主要布局:
<ScrollView
android:id="@+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:fillViewport="true"
android:gravity="top" >
<LinearLayout
android:id="@+id/foodItemActvity_linearLayout_fragments"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
然后,我以编程方式将我的组件添加到linearlayour的id: foodItemActvity_linearLayout_fragments。下面是加载到线性布局中的一个视图。就是这个给我的卷轴带来了麻烦。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/fragment_dds_review_textView_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reviews:"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ListView
android:id="@+id/fragment_dds_review_listView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
我的适配器然后填充这个列表视图。
当我点击主scrollView时,这是一个来自android层级查看器的图像:
如您所见,它排除了评论列表视图。
我应该能够向下滚动页面,看到8个评论,但它只显示了这3个,我可以滚动评论所在的一小部分。我想要一个全局页面滚动
找到了一个解决方案scrollview -> viewpager -> FragmentPagerAdapter -> fragment ->动态listview,但我不是作者。虽然有些bug,但至少还能用
public class CustomPager extends ViewPager {
private View mCurrentView;
public CustomPager(Context context) {
super(context);
}
public CustomPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mCurrentView == null) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int height = 0;
mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = mCurrentView.getMeasuredHeight();
if (h > height) height = h;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void measureCurrentView(View currentView) {
mCurrentView = currentView;
this.post(new Runnable() {
@Override
public void run() {
requestLayout();
}
});
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
}
public class MyPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
private int mCurrentPosition = -1;
public MyPagerAdapter(FragmentManager fm) {
super(fm);//or u can set them separately, but dont forget to call notifyDataSetChanged()
this.fragments = new ArrayList<Fragment>();
fragments.add(new FirstFragment());
fragments.add(new SecondFragment());
fragments.add(new ThirdFragment());
fragments.add(new FourthFragment());
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (position != mCurrentPosition) {
Fragment fragment = (Fragment) object;
CustomPager pager = (CustomPager) container;
if (fragment != null && fragment.getView() != null) {
mCurrentPosition = position;
pager.measureCurrentView(fragment.getView());
}
}
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
片段布局可以是任何东西
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent" tools:context="nevet.me.wcviewpagersample.FirstFragment">
<ListView
android:id="@+id/lv1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#991199"/>
</LinearLayout>
然后在某个地方
lv = (ListView) view.findViewById(R.id.lv1);
lv.setAdapter(arrayAdapter);
setListViewHeightBasedOnChildren(lv);
}
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null)
return;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
View.MeasureSpec.UNSPECIFIED);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0)
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth,
LinearLayout.LayoutParams.WRAP_CONTENT));
view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
好吧,这是我的答案。固定ListView高度的方法足够封闭,但并不完美。如果大多数项目都是相同的高度,那工作得很好。但如果不是,那就有大问题了。我尝试了很多次,当我输出listItem的值时。getMeasureHeight和listItem。getMeasuerWidth到日志中,我看到宽度值变化很大,这在这里是不期望的,因为同一ListView中的所有项应该具有相同的宽度。问题来了:
有些人使用度量(0,0),这实际上使视图在两个方向上都没有边界,宽度也失控了。有些人尝试获取listView的twidth,但它返回0,没有意义。
当我进一步了解android如何渲染视图时,我意识到所有这些尝试都无法达到我搜索的答案,除非这些函数在视图渲染后运行。
这一次我使用getViewTreeObserver在ListView上,我想固定高度,然后添加ongloballayoutlistener。在这个方法中,我声明了一个新的OnGlobalLayoutListener,在这个方法中,getWidth返回ListView的实际宽度。
private void getLayoutWidth(final ListView lv, final int pad){
//final ArrayList<Integer> width = new ArrayList<Integer>();
ViewTreeObserver vto = lv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
lv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
//width.add(layout.getMeasuredWidth());
int width = lv.getMeasuredWidth();
ListUtils.setDynamicHeight(lv, width, pad);
}
});
}
public static class ListUtils {
//private static final int UNBOUNDED = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
public static void setDynamicHeight(ListView mListView, int width, int pad) {
ListAdapter mListAdapter = mListView.getAdapter();
mListView.getParent();
if (mListAdapter == null) {
// when adapter is null
return;
}
int height = 0;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(width - 2*pad, View.MeasureSpec.EXACTLY);
for (int i = 0; i < mListAdapter.getCount(); i++) {
View listItem = mListAdapter.getView(i, null, mListView);
listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
//listItem.measure(UNBOUNDED, UNBOUNDED);
height += listItem.getMeasuredHeight() + 2*pad;
Log.v("ViewHeight :", mListAdapter.getClass().toString() + " " + listItem.getMeasuredHeight() + "--" + listItem.getMeasuredWidth());
}
ViewGroup.LayoutParams params = mListView.getLayoutParams();
params.height = height + (mListView.getDividerHeight() * (mListAdapter.getCount() - 1));
mListView.setLayoutParams(params);
mListView.requestLayout();
}
}
value pad,是我在ListView layout中设置的填充。