listview巢狀gridview,並實現grid元素部分顯示以及點選展開與摺疊
阿新 • • 發佈:2019-01-25
有時我們需要用GridView顯示目錄列表,有時甚至是二級的,即listview每一個item裡面又各自嵌入一個gridview,但是當二級目錄(資料條目)的數量過多時,介面會比較臃腫,這時我們就想要有類似展開與摺疊的效果,作者採用的策略是資料分段的分別顯示,其中對於顯示邊界(處於限制顯示數目的特定位置)的控制元件要有資料的動態更新和點選判斷操作。效果如圖:
具體實現:
一、Activity介面
主Activity,裡面只有一個textview(標題)和listview(主體),其中Listview的介面卡MyAdapter是自寫的(也是實現效果的主要邏輯程式碼)。package com.example.gridinlist; import java.util.Vector; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; public class MainActivity extends Activity { private ListView listView; private MyAdapter adapter; private Vector<String> stringVector = new Vector<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { listView = (ListView) findViewById(R.id.list); adapter = new MyAdapter(this, this.getLayoutInflater(), stringVector); stringVector.add("0"); stringVector.add("1"); stringVector.add("2"); stringVector.add("3"); stringVector.add("4"); stringVector.add("5"); listView.setAdapter(adapter); } }
這裡我們直傳給MyAdapter一個字串向量,為了簡便,不管一級還是二級目錄都是用的這一個向量(實際中每個二級子向量應該都是不同的),使用者可根據需求自行新增或修改(也可以使用Parcel將其封裝為一個二級的資料型別,具體不再贅述)。
Activity佈局檔案
<RelativeLayout 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="${relativePackage}.${activityClass}" > <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_horizontal" android:layout_centerHorizontal="true" android:text="@string/hello_world" /> <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginLeft="7dip" android:layout_marginRight="7dip" android:layout_marginBottom="7dip" android:layout_below="@+id/title" android:cacheColorHint="#00000000" android:drawSelectorOnTop="false" android:listSelector="#00000000" android:scrollbars="none" android:scrollingCache="true" android:drawingCacheQuality="low" android:divider="#00000000" android:dividerHeight="0dip" android:fadingEdgeLength="0.0sp" /> </RelativeLayout>
二、自寫的istview的Adapter(關鍵程式碼)
具體步驟請看程式碼中的註釋,需要注意的是,裡面的GridView使用的是自寫的控制元件,因為若使用Android自帶的GridView,會出現在ListView中只顯示一行grid的情況,這是因為ListView無法動態獲取GridView的數目而無法確定它的高度,因此預設認為只有一行資料。package com.example.gridinlist; import java.util.ArrayList; import java.util.HashMap; import java.util.Vector; import android.annotation.SuppressLint; import android.content.Context; import android.database.DataSetObserver; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; public class MyAdapter extends BaseAdapter { private static final String TAG = "MyAdapter"; private LayoutInflater inflater; private Context context; private Vector<String> vector; private int numGridShowLimit = 4; //Gridview限定顯示數目 /** * 搜尋Adapter初始化 */ public MyAdapter(Context context,LayoutInflater inflater,Vector<String> vector) { this.context = context; this.inflater = inflater; this.vector = vector; } /** * 初始化View */ private static class ViewHolder { private TextView titleTextView; private GridView contentGridView; private GridView contentMoreGridView; } /** * 新增資料 */ @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { final ViewHolder viewHolder; if( convertView == null ) { convertView = inflater.inflate(R.layout.adapter_listview,null); viewHolder = new ViewHolder(); viewHolder.titleTextView = (TextView) convertView.findViewById(R.id.list_txt_title); viewHolder.contentGridView = (GridView) convertView.findViewById(R.id.list_grid); viewHolder.contentMoreGridView = (GridView) convertView.findViewById(R.id.list_grid_more); convertView.setTag(viewHolder); } else viewHolder = (ViewHolder) convertView.getTag(); try { if(vector != null && vector.size() > 0) { final String category = vector.get(position); if(category != null) { viewHolder.titleTextView.setText("list item "+category); } if (vector.size() > 0) { final ArrayList<HashMap<String, Object>> categoryList = new ArrayList<HashMap<String, Object>>(); final ArrayList<HashMap<String, Object>> categorySubList1 = new ArrayList<HashMap<String, Object>>(); final ArrayList<HashMap<String, Object>> categorySubList2 = new ArrayList<HashMap<String, Object>>(); //先封裝整個資料向量到categoryList if (vector != null && vector.size() > 0) { for (int i = 0; i < vector.size(); i++) { String o = vector.get(i); if (o != null) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("ItemText", "grid" + o); categoryList.add(map); } } } final int mypos = position; //當資料向量長度大於限定顯示的grid數目時,將整個資料向量分成兩段 if (vector.size() > numGridShowLimit) { //封裝前段資料到categorySubList1 for (int i = 0; i < numGridShowLimit; i++) { String o = vector.get(i); if (o != null) { if (i==numGridShowLimit-1) { HashMap<String, Object> map = new HashMap<String, Object>(); if (viewHolder.contentMoreGridView.getVisibility()==View.GONE) { //若處於摺疊狀態則將限定數目的位置的資料修改為“+”(用於點選展開) map.put("ItemText", "" + "+"); }else { //若處於展開狀態則限定數目的位置的資料正常顯示 map.put("ItemText", "grid" + o); } categorySubList1.add(map); }else { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("ItemText", "grid" + o); categorySubList1.add(map); } } } //封裝後段資料到categorySubList2 for (int i = numGridShowLimit; i < vector.size(); i++) { String o = vector.get(i); if (o != null) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("ItemText", "grid" + o); categorySubList2.add(map); } } HashMap<String, Object> map = new HashMap<String, Object>(); map.put("ItemText", "-"); //在第二段的最後新增一個“-”資料(用於點選摺疊) categorySubList2.add(map); //建立第一部分GridView的adapter final SimpleAdapter simpleAdapter1 = new SimpleAdapter(context, categorySubList1, R.layout.adapter_gridview, new String[] { "ItemText" }, // 對應map的Key new int[] { R.id.ItemText }); // 對應R的Id viewHolder.contentGridView.setAdapter(simpleAdapter1); //建立第二部分GridView的adapter final SimpleAdapter simpleAdapter2 = new SimpleAdapter(context, categorySubList2, R.layout.adapter_gridview, new String[] { "ItemText" }, // 對應map的Key new int[] { R.id.ItemText }); // 對應R的Id viewHolder.contentMoreGridView.setAdapter(simpleAdapter2); //設定第二部分GridView的adapter中的具體item點選事件 viewHolder.contentMoreGridView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> AdapterView, View view,int pos, long row) { if (categoryList.size()>numGridShowLimit && pos==categoryList.size()-numGridShowLimit) { //若點選末尾的“-”,則將gridview摺疊,並修改第一部分最後位置為“+”(可展開狀態) View rel = (View) viewHolder.contentGridView.getChildAt(numGridShowLimit-1); TextView tv = (TextView) rel.findViewById(R.id.ItemText); tv.setText("+"); viewHolder.contentMoreGridView.setVisibility(View.GONE); }else { view.setTag(mypos*100+numGridShowLimit+pos); Toast.makeText(context, " list position:"+ mypos+"\ngrid position:"+pos, Toast.LENGTH_SHORT).show(); } } }); } else { //若資料向量數目不大於限定的顯示數目,則正常建立第一部分GridView的adapter(直接使用整體資料categoryList) final SimpleAdapter simpleAdapter = new SimpleAdapter(context, categoryList, R.layout.adapter_gridview, new String[] { "ItemText" }, // 對應map的Key new int[] { R.id.ItemText }); // 對應R的Id viewHolder.contentGridView.setAdapter(simpleAdapter); } //設定第一部分GridView的adapter中的具體item點選事件 viewHolder.contentGridView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> AdapterView, View view,int pos, long row) { if (categoryList.size()>numGridShowLimit && pos==numGridShowLimit-1) { TextView tv = (TextView) view.findViewById(R.id.ItemText); String content = tv.getText().toString(); if (content.equals("+")) { //若點選“+”,則進行展開操作,即顯示第二部分gridview,並修改最後位置為“+” tv.setText("grid"+vector.get(numGridShowLimit-1)); viewHolder.contentMoreGridView.setVisibility(View.VISIBLE); }else { view.setTag(mypos*100+pos); Toast.makeText(context, " list position:"+ mypos+"\ngrid position:"+pos, Toast.LENGTH_SHORT).show(); } }else { view.setTag(mypos*100+pos); Toast.makeText(context, " list position:"+ mypos+"\ngrid position:"+pos, Toast.LENGTH_SHORT).show(); } } }); } } } catch (Exception e) { e.printStackTrace(); Log.e(TAG, "Exception"); } return convertView; } @Override public int getCount() { return vector.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public void unregisterDataSetObserver(DataSetObserver observer) { if (observer != null) { super.unregisterDataSetObserver(observer); } } }
解決方法是:在自寫的GridView裡面,需要重寫onMeasure方法,這樣就可以得到GridView的高度了,程式碼如下:
package com.example.gridinlist;
import android.widget.GridView;
public class MyGridView extends GridView
{
public MyGridView(android.content.Context context,
android.util.AttributeSet attrs)
{
super(context, attrs);
}
/**
* 重寫的onMeasure方法
*/
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
ListView的item佈局檔案:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dip"
android:layout_marginBottom="1dip"
android:orientation="vertical"
android:baselineAligned="false"
android:background="#ffffff"
>
<RelativeLayout
android:id="@+id/list_rel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:layout_marginBottom="10dip"
>
<ImageView
android:id="@+id/list_img_icon"
android:layout_width="3dip"
android:layout_height="17dip"
android:layout_marginLeft="15dip"
android:contentDescription="@null"
android:scaleType="fitXY"
android:layout_centerVertical="true"
android:src="@drawable/selected_orange"
android:visibility="visible" />
<TextView
android:id="@+id/list_txt_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/list_img_icon"
android:layout_marginLeft="7dip"
android:layout_marginRight="7dip"
android:gravity="center"
android:layout_centerVertical="true"
android:singleLine="true"
/>
</RelativeLayout>
<com.example.gridinlist.MyGridView
android:id="@+id/list_grid"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="1dip"
android:columnWidth="70dip"
android:horizontalSpacing="10dip"
android:verticalSpacing="10dip"
android:listSelector="@android:color/transparent"
android:numColumns="4"
android:paddingLeft="15dip"
android:paddingRight="15dip"
android:scrollbars="none"
android:stretchMode="columnWidth"
android:visibility="visible" >
</com.example.gridinlist.MyGridView>
<com.example.gridinlist.MyGridView
android:id="@+id/list_grid_more"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="10dip"
android:layout_marginBottom="1dip"
android:columnWidth="70dip"
android:horizontalSpacing="10dip"
android:verticalSpacing="10dip"
android:listSelector="@android:color/transparent"
android:numColumns="4"
android:paddingLeft="15dip"
android:paddingRight="15dip"
android:scrollbars="none"
android:stretchMode="columnWidth"
android:visibility="gone" >
</com.example.gridinlist.MyGridView>
</LinearLayout>
裡面包含一個標題,以及兩個自寫的GridView(一個顯示前面部分,另一個顯示剩下的,點選展開與摺疊其實就是第二個GridView的顯示與隱藏)GridView的item佈局檔案:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/ItemText"
android:layout_width="70dip"
android:layout_height="32dip"
android:background="@drawable/btn_txt_bg"
android:text=""
android:gravity="center"
/>
</RelativeLayout>
只是簡單的一個TextView,使用者想擴充套件或豐富可自行修改。程式碼下載連線:http://download.csdn.net/detail/duguju/9233759