第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開(kāi)發(fā)者教程

Android 入門(mén)教程

菜單類控件
菜單:Menu
并發(fā)編程
多線程

本節(jié)學(xué)習(xí)一個(gè)可折疊的 ListView,可以用在一些需要分類的場(chǎng)景下。通過(guò) ExpandableListView 我們可以首先在 ListView 上展示大的分類,當(dāng)點(diǎn)擊某個(gè)類別的時(shí)候再將 ListView 做一個(gè)展開(kāi),展示該類下的所有子類供用戶選擇。它與 ListView 的不同主要是 ExpandableListView 提供了兩級(jí)列表,可以方便的做伸展和收縮。

1. ExpandableListView 的特性

ExpandableListView 繼承自 ListView,這意味著它擁有 ListView 的所有屬性,是 ListView 的升級(jí)版。它在 ListView 的基礎(chǔ)上增加了子列表,當(dāng)我們點(diǎn)擊某個(gè)列表項(xiàng)的時(shí)候,它會(huì)展開(kāi)顯示所有的子 item;當(dāng)我們?cè)俅吸c(diǎn)擊該列表項(xiàng)的時(shí)候,它會(huì)收縮隱藏所有的子 item,其中子 item 相當(dāng)于是一個(gè) ListView,我們可以給它設(shè)置不同的列表樣式及點(diǎn)擊事件,通常適用于有兩級(jí)分類并且子類比較多的列表場(chǎng)景。

2. ExpandableListView 的基本使用方法

2.1 常用屬性

  • android:childDivider:
    設(shè)置子列表項(xiàng)的分割線樣式,可以通過(guò) drawable 或者 color 資源的方式進(jìn)行配置
  • android:childIndicator:
    設(shè)置顯示在子列表項(xiàng)旁邊的 View,一般用作該列表項(xiàng)的指示標(biāo)注
  • android:childIndicatorEnd:
    設(shè)置子列表指示View的終止位置邊界
  • android:childIndicatorLeft:
    設(shè)置子列表指示View的左邊界
  • android:childIndicatorRight:
    設(shè)置子列表指示View的右邊界
  • android:childIndicatorStart:
    設(shè)置子列表指示View的起始位置邊界
  • android:groupIndicator:
    當(dāng)前分類組旁邊的指示 View
  • android:indicatorEnd:
    指示 View 的終止位置邊界
  • android:indicatorLeft:
    指示 View 的左邊界
  • android:indicatorRight:
    指示 View 的右邊界
  • android:indicatorStart:
    指示 View 的起始位置邊界

2.2 常用 API

  • setChildIndicator(Drawable):
    設(shè)置展示在子列表項(xiàng)旁邊的指示 View 的樣式資源
  • setGroupIndicator(Drawable) :
    設(shè)置展示在主列表項(xiàng)旁邊的指示 View 的樣式資源,這個(gè)不會(huì)因?yàn)橹髁斜眄?xiàng)的伸展或者收縮而改變
  • getGroupView():
    返回這一組列表的頭 View
  • getChildView():
    返回列表的子列表項(xiàng)

2.3 事件監(jiān)聽(tīng)器

  • ExpandableListView.OnChildClickListener:
    該接口當(dāng)中只有一個(gè)回調(diào)方法:

    public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id)
    

    當(dāng)我們點(diǎn)擊一個(gè)子列表項(xiàng)的時(shí)候會(huì)回調(diào)此方法,參數(shù)解析

    • ExpandableListView parent:被點(diǎn)擊的 ExpandableListView 對(duì)象
    • View v:被點(diǎn)擊的具體 item 對(duì)象
    • int groupPosition:被點(diǎn)擊的 item 所在組在主列表的位置
    • int childPosition:被點(diǎn)擊的 item 在當(dāng)前組內(nèi)的位置
  • ExpandableListView.OnGroupClickListener:
    接口中只有一個(gè)回調(diào)方法:

    public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id)
    

該方法監(jiān)聽(tīng)某個(gè)組的點(diǎn)擊事件,當(dāng)該組內(nèi)有任意 item 被點(diǎn)擊是回調(diào),參數(shù)詳情參見(jiàn)onGroupClick方法的解析

  • ExpandableListView.OnGroupCollapseListener:
    只需要實(shí)現(xiàn)一個(gè)方法:
public void onGroupCollapse(int groupPosition)

當(dāng)某個(gè)組被折疊收縮的時(shí)候會(huì)回調(diào)此方法,參數(shù)表示被收縮的組在整個(gè)主列表中的位置

  • ExpandableListView.OnGroupExpandListener:
    該接口同樣是需要實(shí)現(xiàn)一個(gè)方法:
    public void onGroupExpand(int groupPosition)
    

當(dāng)某個(gè)組被展開(kāi)的時(shí)候回調(diào)此方法

3. ExpandableListView 示例

ExpandableListView 主要是在 ListView 的基礎(chǔ)之上加上了折疊的分類效果,所以本節(jié)就通過(guò) ExpandableListView 實(shí)現(xiàn)對(duì)數(shù)據(jù)的二級(jí)分類列表效果,大類就用大家比較熟悉的某競(jìng)技游戲里面的英雄分類,而子類就是該類別里面的幾個(gè)英雄。
PS:英雄分類仁者見(jiàn)仁智者見(jiàn)智,青銅選手求各位骨灰玩家輕拍

3.1 編寫(xiě) Activity 的布局文件

和前幾節(jié)的例子一樣,我們僅需要在根布局中防止一個(gè) ExpandableListView 即可,然后設(shè)置上相應(yīng)的屬性,如下:

<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/expandableListView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:divider="@android:color/darker_gray"
    android:dividerHeight="0.5dp"
    android:indicatorLeft="?android:attr/expandableListPreferredItemIndicatorLeft"
    android:padding="30dp" />

3.2 編寫(xiě)列表布局

列表布局類似 ListView 里面的 item 布局,但是由于 ExpandableListView 有主類和子類區(qū)分,所以這里需要提供兩套布局以適應(yīng)主列表和展開(kāi)后的子列表:

  • 主列表布局 list_group.xml :
     <TextView xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/listTitle"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
      android:paddingTop="10dp"
      android:paddingBottom="10dp"
      android:textColor="@android:color/black" />
    

為了突出大分類,字體設(shè)置為黑體。

  • 子列表布局 list_item.xml :
    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/expandedListItem"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft"
      android:paddingTop="10dp"
      android:paddingBottom="10dp" />
    

3.3 編寫(xiě)數(shù)據(jù)集合

本節(jié)數(shù)據(jù)會(huì)相對(duì)較多,并且有兩級(jí)分類,為了代碼結(jié)構(gòu)清晰這里將數(shù)據(jù)單獨(dú)抽離出來(lái),與 Activity 的業(yè)務(wù)代碼隔離開(kāi),新建一個(gè)數(shù)據(jù)集類 DataCollection.java:

package com.emercy.myapplication;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class DataCollection {

    // 通過(guò)map存放每一個(gè)大類,key是大類類別名,value是子類List
    private static HashMap<String, List<String>> mExpandableListData = new HashMap<>();

    private static final String MASTER = "法師";
    private static final String ASSASSINATOR = "刺客";
    private static final String SHOOTER = "射手";
    private static final String TANK = "對(duì)抗";
    private static final String ASSIST = "輔助";

    // 類加載的時(shí)候初始化數(shù)據(jù)
    static {
        // 創(chuàng)建子類列表,存放在List當(dāng)中
        List<String> master = new ArrayList<>();
        master.add("安琪拉");
        master.add("西施");
        master.add("沈夢(mèng)溪");
        master.add("嫦娥");
        master.add("上官婉兒");
        master.add("不知火舞");

        List<String> assassinator = new ArrayList<>();
        assassinator.add("馬超");
        assassinator.add("鏡");
        assassinator.add("蘭陵王");
        assassinator.add("孫悟空");
        assassinator.add("娜可露露");
        assassinator.add("元歌");

        List<String> shooter = new ArrayList<>();
        shooter.add("狄仁杰");
        shooter.add("伽羅");
        shooter.add("蒙犽");
        shooter.add("魯班七號(hào)");
        shooter.add("孫尚香");
        shooter.add("后羿");

        List<String> tank = new ArrayList<>();
        // 咦?為什么馬超出現(xiàn)了兩次?
        // 因?yàn)樽髡呔徒旭R超
        tank.add("馬超");
        tank.add("蓋倫");
        tank.add("羋月");
        tank.add("鎧");
        tank.add("典韋");

        List<String> assist = new ArrayList<>();
        assist.add("蔡文姬");
        assist.add("小明");
        assist.add("莊周");
        assist.add("魯班");
        assist.add("東皇太一");

        // 將所有的子類List作為Value存放到大類中
        mExpandableListData.put(MASTER, master);
        mExpandableListData.put(ASSASSINATOR, assassinator);
        mExpandableListData.put(SHOOTER, shooter);
        mExpandableListData.put(TANK, tank);
        mExpandableListData.put(ASSIST, assist);
    }

    static HashMap<String, List<String>> getData() {
        return mExpandableListData;
    }
}

該類是一個(gè)靜態(tài)工具類,里面只有一個(gè)靜態(tài)成員變量,用一個(gè) map 來(lái)保存所有的列表項(xiàng)。map 的 key 是大類的類別名稱,value 是子類的 List;子類通過(guò)一個(gè) List 來(lái)存儲(chǔ)所有的子類 item,最后通過(guò)getData()接口對(duì)外暴露數(shù)據(jù)集合。

3.4 編寫(xiě) Adapter

ExpandableListView 的 Adapter 有些不一樣,因?yàn)樗枰獏^(qū)分主類別和子類別,會(huì)多一個(gè) group 的概念,這里采用的是 BaseExpandableListAdapter。相比前幾節(jié)使用的 baseAdapter 大體上的回調(diào)方法都類似,只是多了一些對(duì) group 的處理。

比如 baseAdapter 的getView在 BaseExpandableListAdapter 里面分成了getGroupViewgetChildView分別用來(lái)設(shè)置主類別的 item 和子類別的 item。結(jié)合 BaseAdapter 的回調(diào)方法不難理解 BaseExpandableListAdapter,代碼如下:

package com.emercy.myapplication;

import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;

import java.util.HashMap;
import java.util.List;

public class MyExpandableListAdapter extends BaseExpandableListAdapter {

    private Context mContext;
    private List<String> mHeroCategory;
    private HashMap<String, List<String>> mHeroName;

    public MyExpandableListAdapter(Context context, List<String> expandableListTitle,
                                   HashMap<String, List<String>> expandableListDetail) {
        mContext = context;
        mHeroCategory = expandableListTitle;
        mHeroName = expandableListDetail;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        return mHeroName.get(mHeroCategory.get(groupPosition)).get(childPosition);
    }

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

    @Override
    public View getChildView(int groupPosition, final int childPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {
        final String expandedListText = (String) getChild(groupPosition, childPosition);
        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_item, null);
        }
        TextView expandedListTextView = convertView.findViewById(R.id.expandedListItem);
        expandedListTextView.setText(expandedListText);
        return convertView;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return mHeroName.get(mHeroCategory.get(groupPosition)).size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return mHeroCategory.get(groupPosition);
    }

    @Override
    public int getGroupCount() {
        return mHeroCategory.size();
    }

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

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
                             View convertView, ViewGroup parent) {
        String listTitle = (String) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_group, null);
        }
        TextView listTitleTextView = convertView
                .findViewById(R.id.listTitle);
        listTitleTextView.setTypeface(null, Typeface.BOLD);
        listTitleTextView.setText(listTitle);
        return convertView;
    }

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

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }
}

如果有對(duì)這些回調(diào)接口的實(shí)現(xiàn)不太理解的,可以回顧一下第24節(jié)中講 ListView 的時(shí)候?qū)?BaseAdapter 做的詳細(xì)講解。

3.5 編寫(xiě) MainActivity

前面已經(jīng)實(shí)現(xiàn)了布局、數(shù)據(jù)、適配器等模塊的編寫(xiě),整個(gè) ExpandableListView 的框架就已經(jīng)搭建完畢了。雖然本節(jié)的示例比較簡(jiǎn)單,代碼量也比較少,但是也希望大家在學(xué)習(xí)過(guò)程中能夠注重模塊的編寫(xiě)順序,循序漸進(jìn)的培養(yǎng)自己搭建一個(gè)更完整的更大型架構(gòu)的能力。
框架搭建完畢就可以進(jìn)入業(yè)務(wù)代碼的編寫(xiě)了,在MainActivity中我們主要做以下4件事:

  1. 設(shè)置布局文件并從布局文件中拿到 ExpandableListView 實(shí)例;
  2. 獲取數(shù)據(jù)集(實(shí)際使用中可能是從網(wǎng)絡(luò)獲取或者本地讀?。?;
  3. 創(chuàng)建適配器,并為 ExpandableListView 實(shí)例設(shè)置適配器;
  4. 為 ExpandableListView 添加相應(yīng)的事件監(jiān)聽(tīng)器,并實(shí)現(xiàn)監(jiān)聽(tīng)器接口中的回調(diào)方法。

按照以上 4 步來(lái)做即可,代碼如下:

package com.emercy.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MainActivity extends Activity {

    HashMap<String, List<String>> expandableListDetail;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 1.設(shè)置布局文件并從布局文件中拿到 ExpandableListView 實(shí)例;
        setContentView(R.layout.activity_main);
        ExpandableListView listView = findViewById(R.id.expandableListView);
        // 2. 獲取數(shù)據(jù)集(實(shí)際使用中可能是從網(wǎng)絡(luò)獲取或者本地讀?。?/span>
        expandableListDetail = DataCollection.getData();
        final List<String> heroCategory = new ArrayList<>(expandableListDetail.keySet());
        // 3. 創(chuàng)建適配器,并為 ExpandableListView 實(shí)例設(shè)置適配器
        ExpandableListAdapter adapter = new MyExpandableListAdapter(this, heroCategory, expandableListDetail);
        listView.setAdapter(adapter);
        // 4. 為 ExpandableListView 添加相應(yīng)的事件監(jiān)聽(tīng)器,并實(shí)現(xiàn)監(jiān)聽(tīng)器接口中的回調(diào)方法
        listView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {

            @Override
            public void onGroupExpand(int groupPosition) {
                Toast.makeText(getApplicationContext(), heroCategory.get(groupPosition)
                                + " 列表展開(kāi)", Toast.LENGTH_SHORT).show();
            }
        });

        listView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {

            @Override
            public void onGroupCollapse(int groupPosition) {
                Toast.makeText(getApplicationContext(), heroCategory.get(groupPosition)
                                + " 列表折疊", Toast.LENGTH_SHORT).show();

            }
        });

        listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                Toast.makeText(getApplicationContext(), heroCategory.get(groupPosition)
                        + " -> " + expandableListDetail.get(heroCategory.get(groupPosition))
                        .get(childPosition), Toast.LENGTH_SHORT
                ).show();
                return false;
            }
        });
    }
}

編譯運(yùn)行之后,界面上會(huì)展示一個(gè) 5 大英雄類別的 ListView,點(diǎn)擊每個(gè)類別系統(tǒng)會(huì)回調(diào)onGroupExpand方法,我們?cè)诋?dāng)中打印出當(dāng)前被展開(kāi)的類別名;然后會(huì)彈出該類下的英雄名稱,點(diǎn)擊英雄名稱系統(tǒng)會(huì)回調(diào)onChildClick方法,我們?cè)诜椒ㄖ写蛴〕霰稽c(diǎn)擊的英雄名稱;最后我們可以點(diǎn)擊已經(jīng)展開(kāi)的英雄類別,系統(tǒng)會(huì)將點(diǎn)擊的類別恢復(fù)折疊狀態(tài)同時(shí)回調(diào)onGroupCollapse方法,在其中我們打印出被折疊的類別名稱,最終效果如下:

ExpandableListView示例

4. 小結(jié)

本節(jié)學(xué)習(xí)了 ListView 的升級(jí)版,ExpandableListView 繼承自 ListView,在 ListView 的基礎(chǔ)之上加上了二級(jí)分類,所以引入了 group 的概念。在布局文件中除了正常的列表 item 外還需要有一個(gè) group 的布局;

ExpandableListAdapter 也多了一些針對(duì) group 的處理;數(shù)據(jù)也需要分主類別和子類別,我們先將英雄分為 5 大類,接著在 5 個(gè)大類下分別列舉了一些該類的英雄名稱,最終通過(guò) ExpandableListAdapter 實(shí)現(xiàn)了一個(gè)英雄分類的示例 App。