PS:我們都知道微信,更是知道朋友圈,很多人在朋友圈里賣起了化妝品,打入廣告等為自己做一下推廣,里面會附帶一寫好看的圖片,上面有標題,有描述,整體布局每場的美觀,那么這是怎么實現的呢,有些人可能會單個使用ListView,也會使用GridView,那么listview嵌套gridview你使用過嗎,現在先看一張圖,

這張圖是不是很熟悉,沒錯這個就是朋友圈,里面有一個,里面的布局我都畫出來了,我不知道微信具體怎么實現的,但是我們會用安卓原生的方法去實現這樣的布局,並有實實在在的數據。
思路:
首頁這是一個可以滑動的view,但是分為標題(用戶名)和內容,並且內容下面還有圖片,圖片也是不確定的。這里就用ExpandableListView+GridView,如果有人不了解這個ExpandableListView的話,看完這篇基本用法就會了。
步驟:
- 總布局的創建,里面只要一個ExpandableListView控件。
- ExpandableListView的item布局創建,本布局用最傳統的做法分為Group和Child布局。
- Group布局只顯示一個用戶名
- Child布局就要為描述內容和GridView(存放圖片)。
- ExpandableListView適配器創建。
- 數據加載。
查看效果圖,這個圖在上傳的時候壓縮了就變的模糊了,請諒解。

1: 總布局的創建,里面只要一個ExpandableListView控件。
這里文件非常簡單,只有一個控件,當然ExpandableListView也是有很多屬性的。這里都沒有寫,去掉箭頭,在Activity中動態添加。這里布局文件我都省去了根布局LinearLayout。
<ExpandableListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/id_elv"/>
2:ExpandableListView的item布局創建,本布局用最傳統的做法分為Group和Child布局
2.1:這個就比較多了文件,首先來寫一下Group的布局,名字你隨便起,我這里叫grouplayout.xml
<ImageView android:id="@+id/id_group_img" android:layout_width="40dp" android:layout_height="40dp" android:src="@mipmap/ic_launcher"/> <TextView android:id="@+id/id_group_name" android:layout_width="wrap_content" android:layout_height="40dp" android:gravity="center" android:textSize="40px" android:layout_marginLeft="10dp" android:text="name"/>
2.2:其次是Child的布局,名字也是隨便起,我這里叫childlayout.xml
<TextView android:id="@+id/id_dec" android:layout_width="wrap_content" android:layout_height="40dp" android:gravity="center" android:textSize="35px" android:layout_marginLeft="10dp" android:text="describe"/> <GridView android:layout_width="match_parent" android:layout_height="match_parent" android:numColumns="3" android:id="@+id/id_gv"></GridView>
2.3:還有一個布局文件,那就是GridView的item布局
<ImageView android:id="@+id/id_img" android:src="@mipmap/ic_launcher" android:layout_width="match_parent" android:layout_margin="20dp" android:layout_height="100dp" />
3:ExpandableListView適配器創建
適配器的創建才是重點,首先我們對ExpandableListView自定義適配器,然后再在里面嵌套一個GridView的自定義適配器,當然你也可以調用系統的,不過個人覺得自定義有更好的靈活性。在這之前呢,我們需要創建幾個bean類,group里有img圖片和text文字,child有text文字和img圖片數組。因為用戶可能會多發幾張照片,不光是一個。下面有兩個class,稍微看一下就Ok了,不用太在意非要一樣。
package mus.cn.shopeffect; /** * Created by cMusketeer on 18/5/23. * * @author 劉志通 */ public class GroupBean { String groupImg,name; public String getGroupImg() { return groupImg; } public void setGroupImg(String groupImg) { this.groupImg = groupImg; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
import java.util.List; /** * Created by cMusketeer on 18/5/23. * * @author 劉志通 */ public class ChildBean { public String childDesc; public List<String> childImg; public String getChildDesc() { return childDesc; } public void setChildDesc(String childDesc) { this.childDesc = childDesc; } public List<String> getChildImg() { return childImg; } public void setChildImg(List<String> childImg) { this.childImg = childImg; } }
創建Adapter,首先我們要繼承adapter,這里和以前的就不一樣了,我們要繼承BaseExpandableListAdapter,當你繼承后,系統就會讓你重寫里面的方法,方法有很多,不用全部,有如下幾個就行了(有的小伙伴系統提示的全部繼承,還缺一個)。
3.1:方法作用詳情(沒有先后順序,古無序號)
首先定義變量(這里listChild為什么list里泛型還是list,我在Activity中解釋)
public Context context; public List<GroupBean> listGroup; public List<List<ChildBean>> listChild;
組Group(父)的長度
@Override public int getGroupCount() { return listGroup.size(); }
某個組中child(子)的長度
@Override public int getChildrenCount(int groupPosition) { return listChild.get(groupPosition).size(); }
拿到父的項
@Override public Object getGroup(int groupPosition) { return listGroup.get(groupPosition); }
拿到組(父)中子的項
@Override public Object getChild(int groupPosition, int childPosition) { return listChild.get(groupPosition).get(childPosition); }
拿到父、子id
@Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; }
組和子元素是否持有穩定的ID。
@Override public boolean hasStableIds() { return false; }
返回值:如果當前適配器不包含任何數據則返回True。經常用來決定一個空視圖是否應該被顯示。
@Override public boolean isEmpty() { return false; }
子項是否可以選中
@Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; }
3.2:補充:這里還有一些方法,你如果是沒有用的話,就不用寫。
public abstract void onGroupCollapsed (int groupPosition) 當組收縮狀態的時候此方法被調用。 參數: groupPosition 收縮狀態的組索引 public abstract void onGroupExpanded(int groupPosition) 當組展開狀態的時候此方法被調用。
3.3:下面才是重點,分別是getGroupView和getChildView用來顯示視圖。具體看注釋。
圖片加載庫Glide依賴:compile 'com.github.bumptech.glide:glide:3.7.0'
@Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { ViewHoldeGroup viewHoldeGroup; if (convertView == null) {//沒有視圖時創建 convertView = LayoutInflater.from(context).inflate(R.layout.grouplayout, null);//添加布局文件 viewHoldeGroup = new ViewHoldeGroup();//創建holder對象 viewHoldeGroup.imageView = (ImageView) convertView.findViewById(R.id.id_group_img);//拿到控件 viewHoldeGroup.textView = (TextView) convertView.findViewById(R.id.id_group_name); convertView.setTag(viewHoldeGroup); } else { viewHoldeGroup = (ViewHoldeGroup) convertView.getTag(); }//這里我用的Glide框架,用來加載網絡圖片的。 Glide.with(context).load(listGroup.get(groupPosition).getGroupImg()).asBitmap().into(viewHoldeGroup.imageView); viewHoldeGroup.textView.setText(listGroup.get(groupPosition).getName()); return convertView; } class ViewHoldeGroup { ImageView imageView; TextView textView; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { ViewHoldeChild viewHoldeChild; GVAdapter gvAdapter; if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.childlayout, null); viewHoldeChild = new ViewHoldeChild(); viewHoldeChild.gridView = (GridView) convertView.findViewById(R.id.id_gv); viewHoldeChild.textView = (TextView) convertView.findViewById(R.id.id_dec); convertView.setTag(viewHoldeChild); } else { viewHoldeChild = (ViewHoldeChild) convertView.getTag(); } viewHoldeChild.textView.setText(listChild.get(groupPosition).get(childPosition).getChildDesc()); gvAdapter = new GVAdapter(context, listChild.get(groupPosition).get(childPosition).getChildImg());//適配器 viewHoldeChild.gridView.setAdapter(gvAdapter); return convertView; } class ViewHoldeChild { TextView textView; GridView gridView; }
到這里呢我們可以看到Gridview的適配器,寫在了ExpandableListView適配器的里面,數據還是一樣的傳遞。GridView的適配器我就不寫了,太簡單,寫上代碼量就大了。
4:數據加載
4.1:Activity中最后一步,下面有解釋。
//添加組數據 List<GroupBean> listGroup = new ArrayList<>(); GroupBean groupBean; for (int i = 0; i < 10; i++) { groupBean = new GroupBean(); groupBean.setGroupImg("https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1116338067,147640299&fm=27&gp=0.jpg"); groupBean.setName("測試"); listGroup.add(groupBean); } //添加組中子的數據,這里我解釋一下list嵌套list,比如說一共是10個組,每個組里有一個子項目,每個子項目中又有2個圖片 List<List<ChildBean>> listChild = new ArrayList<>(); List<ChildBean> list;//子的數據 List<String> liImg;//子中圖片的數據 ChildBean childBean; for (int i = 0; i < 10; i++) { list = new ArrayList<>(); for (int j = 0; j < 1; j++) { childBean = new ChildBean(); liImg = new ArrayList<>(); for (int k = 0; k < 2; k++) {//圖片加載 liImg.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1527344951394&di=6dc7f379165a02c45e8df43106dbb153&imgtype=0&src=http%3A%2F%2Fimg.sc115.com%2Fuploads%2Fsc%2Fjpgs%2F1407%2Fapic4833_sc115.com.jpg"); } childBean.setChildImg(liImg); childBean.setChildDesc("我是一個描述,我在圖片的上面"); list.add(childBean);//添加到子中 } listChild.add(list); } ExpandableAdapter expandableAdapter = new ExpandableAdapter(this, listGroup, listChild); lv.setAdapter(expandableAdapter); //默認展開 if (expandableAdapter != null) { for (int i = 0; i < listGroup.size(); i++) { lv.expandGroup(i); } } //去除箭頭 lv.setGroupIndicator(null);
List<List<ChildBean>>解釋,紅色的是組,里面的是子,每個組里不一定有幾個子(這里畫了兩個)。

