ScrollView 中的两个 ListView
Two ListViews in a ScrollView
我知道将两个 ListView 放在一个 ScrollView 中不是最佳做法。然而,这是我能想到的最好的解决方案:
我想要两个列表(第一个包含 1-5 个项目,最后一个最多包含 20 个项目)在可滚动视图中彼此下方,每个列表都有自己的 header。 ListViews 本身不应该是可滚动的,它们应该只是改变高度来包裹它们的内容。可滚动部分将由 ScrollView 处理。
因为 ListView 本身不支持此功能,所以我使用以下代码:
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
Log.d("DEBUG", "TotalHeight:" + totalHeight);
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listAdapter.getCount() * listView.getDividerHeight());
listView.setLayoutParams(params);
listView.requestLayout();
}
但是,这会使 ListView 比应有的大 10 倍。如果我搜索我遇到的问题,我总能找到上述解决方案,但对我来说这似乎不起作用。
有没有办法修复我的代码,或者有更好的方法来解决这个问题?
XML:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.miscoriadev.svvirgoapp.fragments.frag_activiteiten"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tv_acti_komende_activiteiten"
android:textSize="32sp"
android:text="Komende activiteiten"
android:textColor="@color/TextColorDark"
android:gravity="center"/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_acti_komende_activiteiten"
android:id="@+id/lv_komende_activiteiten">
</ListView>
<TextView
android:paddingTop="@dimen/activity_vertical_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="32sp"
android:text="Afgelopen activiteiten"
android:textColor="@color/TextColorDark"
android:gravity="center"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:id="@+id/tv_acti_afgelopen_activiteiten"
android:layout_below="@id/lv_komende_activiteiten"/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_acti_afgelopen_activiteiten"
android:id="@+id/lv_afgelopen_activiteiten">
</ListView>
</RelativeLayout>
我通过从 LinearLayout 创建自己的列表 UI 元素解决了我的问题,方法是像 ListAdapter 对 ListView 所做的那样将视图扩展到其中。
但是有点粗糙,您可以轻松地重写此代码以接受 ListAdapter 对象作为项目源。通过重写 setListItems() 方法以通过 ListAdapter 对象的 getView() 方法获取它的视图。
package com.miscoriadev.svvirgoapp.util;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.miscoriadev.svvirgoapp.MainActivity;
import com.miscoriadev.svvirgoapp.R;
import java.util.ArrayList;
/**
* Created by milanvandijck on 14/10/2016.
*/
public class UnscrollableListView extends LinearLayout{
private Context context;
private LayoutInflater inflater;
private MainActivity mainActivity;
public UnscrollableListView(Context context) {
super(context);
this.context = context;
this.mainActivity = (MainActivity)context;
this.setOrientation(LinearLayout.VERTICAL);
if(!this.isInEditMode()) {
inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
}
}
public UnscrollableListView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.mainActivity = (MainActivity)context;
this.setOrientation(LinearLayout.VERTICAL);
if(!this.isInEditMode()) {
inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
}
}
public void setListItems(ArrayList<ActivityItem> list){
for (int i = 0; i <= list.size()-1; i++){
UnscrollableListView.viewHolder holder = new UnscrollableListView.viewHolder();
View rowView;
final ActivityItem item = list.get(i);
Log.d(getClass().getName(), "Adding view: " + item.getTitle());
// Check if there are activities
if (item.getTitle().equals("0_0") && item.getLocation().equals("0_0")){
rowView = inflater.inflate(R.layout.activiteiten_listitem_emptylist, null);
this.addView(rowView);
}
rowView = inflater.inflate(R.layout.activiteiten_listitem, null, false);
holder.tv_name=(TextView) rowView.findViewById(R.id.eventName);
holder.tv_date=(TextView) rowView.findViewById(R.id.eventDate);
holder.tv_time=(TextView) rowView.findViewById(R.id.eventTime);
holder.tv_Location= (TextView) rowView.findViewById(R.id.eventLocation);
holder.img_poster=(ImageView) rowView.findViewById(R.id.eventPoster);
holder.tv_name.setText(item.getTitle());
holder.img_poster.setImageBitmap(item.getImage());
holder.tv_date.setText(item.getDateString());
holder.tv_time.setText(item.getTimeString());
holder.tv_Location.setText(item.getLocation());
rowView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
mainActivity.openActivityDetails(item);
}
});
this.addView(rowView, i);
}
this.invalidate();
}
public class viewHolder
{
TextView tv_name;
TextView tv_date;
TextView tv_time;
TextView tv_Location;
ImageView img_poster;
}
}
我知道将两个 ListView 放在一个 ScrollView 中不是最佳做法。然而,这是我能想到的最好的解决方案:
我想要两个列表(第一个包含 1-5 个项目,最后一个最多包含 20 个项目)在可滚动视图中彼此下方,每个列表都有自己的 header。 ListViews 本身不应该是可滚动的,它们应该只是改变高度来包裹它们的内容。可滚动部分将由 ScrollView 处理。
因为 ListView 本身不支持此功能,所以我使用以下代码:
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
Log.d("DEBUG", "TotalHeight:" + totalHeight);
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listAdapter.getCount() * listView.getDividerHeight());
listView.setLayoutParams(params);
listView.requestLayout();
}
但是,这会使 ListView 比应有的大 10 倍。如果我搜索我遇到的问题,我总能找到上述解决方案,但对我来说这似乎不起作用。
有没有办法修复我的代码,或者有更好的方法来解决这个问题?
XML:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.miscoriadev.svvirgoapp.fragments.frag_activiteiten"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tv_acti_komende_activiteiten"
android:textSize="32sp"
android:text="Komende activiteiten"
android:textColor="@color/TextColorDark"
android:gravity="center"/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_acti_komende_activiteiten"
android:id="@+id/lv_komende_activiteiten">
</ListView>
<TextView
android:paddingTop="@dimen/activity_vertical_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="32sp"
android:text="Afgelopen activiteiten"
android:textColor="@color/TextColorDark"
android:gravity="center"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:id="@+id/tv_acti_afgelopen_activiteiten"
android:layout_below="@id/lv_komende_activiteiten"/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_acti_afgelopen_activiteiten"
android:id="@+id/lv_afgelopen_activiteiten">
</ListView>
</RelativeLayout>
我通过从 LinearLayout 创建自己的列表 UI 元素解决了我的问题,方法是像 ListAdapter 对 ListView 所做的那样将视图扩展到其中。
但是有点粗糙,您可以轻松地重写此代码以接受 ListAdapter 对象作为项目源。通过重写 setListItems() 方法以通过 ListAdapter 对象的 getView() 方法获取它的视图。
package com.miscoriadev.svvirgoapp.util;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.miscoriadev.svvirgoapp.MainActivity;
import com.miscoriadev.svvirgoapp.R;
import java.util.ArrayList;
/**
* Created by milanvandijck on 14/10/2016.
*/
public class UnscrollableListView extends LinearLayout{
private Context context;
private LayoutInflater inflater;
private MainActivity mainActivity;
public UnscrollableListView(Context context) {
super(context);
this.context = context;
this.mainActivity = (MainActivity)context;
this.setOrientation(LinearLayout.VERTICAL);
if(!this.isInEditMode()) {
inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
}
}
public UnscrollableListView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.mainActivity = (MainActivity)context;
this.setOrientation(LinearLayout.VERTICAL);
if(!this.isInEditMode()) {
inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
}
}
public void setListItems(ArrayList<ActivityItem> list){
for (int i = 0; i <= list.size()-1; i++){
UnscrollableListView.viewHolder holder = new UnscrollableListView.viewHolder();
View rowView;
final ActivityItem item = list.get(i);
Log.d(getClass().getName(), "Adding view: " + item.getTitle());
// Check if there are activities
if (item.getTitle().equals("0_0") && item.getLocation().equals("0_0")){
rowView = inflater.inflate(R.layout.activiteiten_listitem_emptylist, null);
this.addView(rowView);
}
rowView = inflater.inflate(R.layout.activiteiten_listitem, null, false);
holder.tv_name=(TextView) rowView.findViewById(R.id.eventName);
holder.tv_date=(TextView) rowView.findViewById(R.id.eventDate);
holder.tv_time=(TextView) rowView.findViewById(R.id.eventTime);
holder.tv_Location= (TextView) rowView.findViewById(R.id.eventLocation);
holder.img_poster=(ImageView) rowView.findViewById(R.id.eventPoster);
holder.tv_name.setText(item.getTitle());
holder.img_poster.setImageBitmap(item.getImage());
holder.tv_date.setText(item.getDateString());
holder.tv_time.setText(item.getTimeString());
holder.tv_Location.setText(item.getLocation());
rowView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
mainActivity.openActivityDetails(item);
}
});
this.addView(rowView, i);
}
this.invalidate();
}
public class viewHolder
{
TextView tv_name;
TextView tv_date;
TextView tv_time;
TextView tv_Location;
ImageView img_poster;
}
}