今天要來聊聊關於ExpandableListView

關於ExpandableListView,當時在找資料時發現資訊量比想像中地少(´・д・`)

雖然還不至於要到非得英文搜尋才可以找到你要的資訊

但是就是...比較少就是了XD

絕大多數有寫的都是簡書或者CSDN等大陸的資料(´・_・`)

而且有的還寫得特別複雜,看了都昏了(但是解釋得算很清楚..

OK廢話就先到這裡,我本身對於這個控件只有一個看法...

其實比起控件本身,真正難的是"該如何設計陣列"(╭ರ_⊙)

沒錯,我這樣講好了

舉例RecycleView或者ListView等,這兩項控件都是單層列表

簡而言之只要懂得操作單層的陣列就好(´・з・)

像是

String[] mString = ["1",''2",'3'",''4",''5"];

這種,或是只要輸出只有單層的,就可以完成單層的控件

但是像ExpandableListView,是屬於雙層(´υ`)

所以在陣列的設計上,必須多加考慮才能達到自己想要的效果

 

2020/6/6補充

這邊有雙層清單的進階使用方法,歡迎各位參考哦!

碼農日常-『Android studio』ExpandableListView+長按顯示選單視窗ContextMenu

 

好,廢話到此,上功能與Github

GitHub:

https://github.com/thumbb13555/ExpandableListVIewExample


首先在開始之前,可以找看看Google有沒有提供範例,以及了解基本能用的指令

https://developer.android.com/reference/android/widget/ExpandableListView

https://developer.android.com/reference/android/widget/BaseExpandableListAdapter

好啦...範例貌似沒提供但是有基本Api指令資料

參考看看就好

那麼開始操作

首先請先在onCreate的外面新增一個class

然後紅線下implement methods,加入BaseExpandableListAdapter所繼承過來的方法

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "CommunicationWithBT";
    private MyExpandableListAdapter myExpandableListAdapter;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }

   
    private class MyExpandableListAdapter extends BaseExpandableListAdapter{
        @Override
        public int getGroupCount() {//父陣列長度
            return 0;
        }

        @Override
        public int getChildrenCount(int groupPosition) {//子陣列長度
            return 0;
        }

        @Override
        public Object getGroup(int groupPosition) {
            return null;
        }

        @Override
        public Object getChild(int groupPosition, int childPosition) {
            return null;
        }

        @Override
        public long getGroupId(int groupPosition) {
            return 0;
        }

        @Override
        public long getChildId(int groupPosition, int childPosition) {
            return 0;
        }

        @Override
        public boolean hasStableIds() {
            return false;
        }

        @Override
        public View getGroupView(int groupPosition, boolean isExpanded
                , View convertView, ViewGroup parent) {//設置父項目的View

            return null;
        }

        @Override
        public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {//設置子項目的View
            
            return null;
        }

        @Override
        public boolean isChildSelectable(int groupPosition, int childPosition) {//設置子項目是否可點擊
            return false;
        }
    }
}

注意紅色部分是自定義的命名

在方法裡面簡單解釋幾個會用到的

getGroupCount()為父陣列長度<-第一層

getChildrenCount()為子陣列長度<-第二層

getGroupId() 回傳groupPosition即可

getChildId() 回傳childPosition即可

getGroupView() 設置父層的View

getChildView() 設置子層的View

isChildSelectable() 設置子項目是否可被點擊


可以發現說在方法內有getGroupView() getChildView()

也因此設置時要先新增兩個額外的View介面去處理

啊...突然想到忘了PO Layout..._(┐「ε:)_

activity_main.xml

https://github.com/thumbb13555/ExpandableListVIewExample/blob/master/app/src/main/res/layout/activity_main.xml

https://github.com/thumbb13555/ExpandableListVIewExample/blob/master/app/src/main/res/layout/expandlistview_child.xml

https://github.com/thumbb13555/ExpandableListVIewExample/blob/master/app/src/main/res/layout/expandlistview_item.xml

 

接著要做的事情有二

1.製造資料

2.設置ExpandableListView

 

首先是製造資料

首先在全域變數內宣告以下

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "CommunicationWithBT";
    private MyExpandableListAdapter myExpandableListAdapter;
    private ExpandableListView expandableListView;
    private HashMap<String, ArrayList> mainArray = new HashMap<>();//父層總陣列
    private ArrayList<String> itemName = new ArrayList<>();//父層標題
    private ArrayList<HashMap<String,String>> childArray = new ArrayList<>();//子層陣列

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

         setData();
         .
         .

    }

我是宣告了3+1個陣列拉...當然不一定需要這麼多(紫色部分)

然後在onCreate內新增一副程式setData();

接著在setData()內寫入以下程式

private void setData() {
        for (int i = 0;i<6;i++){//子項目的內容
            HashMap<String,String> childName = new HashMap<>();//子層內容
            childName.put("Child1","項目"+i);
            childName.put("Child2","內容"+i);
            childArray.add(childName);
        }

        for (int i=0;i<4;i++){//父項目的內容
            itemName.add(i,"標題"+i);

            mainArray.put(itemName.get(i),childArray);
        }

        Log.d(TAG, "setData: "+mainArray);

    }

寫到這邊,可以試著先run一次,然後觀察一下logCat內的資訊

陣列為

父層總陣列<父層標題陣列,子層陣列<String,子層內容>>

這個部分每個人的方法跟不一樣,但是發現結果都差不多(・ω・`)………..

在這裡建議,可以試著用自己的方法完成跟我很像的陣列,這樣以後將可更靈活地運用喔(・ω・)b

接著是設置ExpandableListView的部分

請在onCreate裡面加入

expandableListView = findViewById(R.id.expandAbleListView);
expandableListView.setChildDivider(getResources().getDrawable(R.color.greywhite));//可以先不加入,這是去子層底線用的
myExpandableListAdapter = new MyExpandableListAdapter();
expandableListView.setAdapter(myExpandableListAdapter);

全域宣告的部分長這樣,千萬別漏了

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "CommunicationWithBT";
    private MyExpandableListAdapter myExpandableListAdapter;
    private ExpandableListView expandableListView;
    private HashMap<String, ArrayList> mainArray = new HashMap<>();//父層總陣列
    private ArrayList<String> itemName = new ArrayList<>();//父層標題
    private ArrayList<HashMap<String,String>> childArray = new ArrayList<>();//子層陣列

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       expandableListView = findViewById(R.id.expandAbleListView);
       expandableListView.setChildDivider(getResources().getDrawable(R.color.greywhite));//可以先不加入,這是去子層底線用的 
       myExpandableListAdapter = new MyExpandableListAdapter(); 
       expandableListView.setAdapter(myExpandableListAdapter);

}

 

再來設置MyExpandableListAdapter的內容

請按照以下設定

private class MyExpandableListAdapter extends BaseExpandableListAdapter{
        @Override
        public int getGroupCount() {//父陣列長度
            return mainArray.size();
        }

        @Override
        public int getChildrenCount(int groupPosition) {//子陣列長度
            return childArray.size();
        }

        @Override
        public Object getGroup(int groupPosition) {
            return null;
        }

        @Override
        public Object getChild(int groupPosition, int childPosition) {
            return null;
        }

        @Override
        public long getGroupId(int groupPosition) {
            return groupPosition;
        }

        @Override
        public long getChildId(int groupPosition, int childPosition) {
            return childPosition;
        }

        @Override
        public boolean hasStableIds() {
            return false;
        }

        @Override
        public View getGroupView(int groupPosition, boolean isExpanded
                , View convertView, ViewGroup parent) {//設置父項目的View
            if (convertView == null){
                LayoutInflater inflater = (LayoutInflater) MainActivity.this
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(R.layout.expandlistview_item,null);
            }
            convertView.setTag(R.layout.expandlistview_item,groupPosition);
            convertView.setTag(R.layout.expandlistview_item,-1);
            TextView textView = convertView.findViewById(R.id.textView_ItemTitle);
            textView.setText(itemName.get(groupPosition));

            return convertView;
        }

        @Override
        public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
            if (convertView == null){//設置子項目的View
                LayoutInflater inflater = (LayoutInflater) MainActivity.this
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(R.layout.expandlistview_child,null);
            }
            convertView.setTag(R.layout.expandlistview_child,groupPosition);
            convertView.setTag(R.layout.expandlistview_child,-1);
            TextView child1 = convertView.findViewById(R.id.textView_child1);
            TextView child2 = convertView.findViewById(R.id.textView_child2);
            child1.setText(childArray.get(childPosition).get("Child1"));
            child2.setText(childArray.get(childPosition).get("Child2"));
            return convertView;
        }

        @Override
        public boolean isChildSelectable(int groupPosition, int childPosition) {//設置子項目是否可點擊
            return true;
        }
    }

 

可以瞧見他給的Adapter內,大致就是由groupPosition及childPositiion組成

groupPosition是父層的ID

childPositiion是子層的ID

靈活地運用這兩項就可以完成自己想要的樣子囉~


結論

ExpandableListView不能說它是一個不常用的控件

但是的確比起一些常用元件,他的出現頻率是低了點

ExpandableListView最大的難點我覺得是如何使用各種集合陣列拼出自己想要的樣子

我在實際專案中因為我的資料來源是RoomDataBase

因此還要考慮從Room取出來後應該要有的樣子

還有自己的實際需要

今天的教學就到這

希望對你有幫助(・ωー)~☆

arrow
arrow
    創作者介紹
    創作者 碼農日常 的頭像
    碼農日常

    碼農日常大小事

    碼農日常 發表在 痞客邦 留言(2) 人氣()