Android 手風琴效果實現


ExpandableListView 基礎知識  
1. ExpandableListView 的總體概述  
  ExpandableListView 是 android 中可以實現下拉 list 的一個控件,是一個垂直滾動的心事兩個級  
別列表項手風琴試圖,列表項是來自 ExpandableListViewaAdapter,組可以單獨展開。  
2.重要的方法:  
  expandGroup (int groupPos) ;//在分組列表視圖中 展開一組,  
  setSelectedGroup (int groupPosition) ;//設置選擇指定的組。  
  setSelectedChild (int groupPosition, int childPosition, boolean shouldExpandGroup);  
  getPackedPositionGroup (long packedPosition);//返回所選擇的組  
  isGroupExpanded (int groupPosition);//判斷此組是否展開  
  expandableListView.setDivider();這個是設定每個 Group 之間的分割線。  
  expandableListView.setGroupIndicator();這個是設定每個 Group 之前的那個圖標。  
  expandableListView.collapseGroup(int group); 將第 group 組收起  
3. 適配器的介紹  
  ExpandableListAdapter,一個接口,將基礎數據鏈接到一個 ExpandableListView。 此接  
口的實施將提供訪問 Child 的數由組分類實例化的 Child 和 Group配器中常用的重  
要方法:  
  getChildId (int groupPosition, int childPosition) 獲取與在給定組給予孩子相關的數據。  
  getChildrenCount (int groupPosition) 返回在指定 Group 的 Child 數目  
4. 屬性和事件  
1) 在 Android 中對子條目的點擊事件是通過 onChildClick()來實現  
 
2) 對組的點擊事件是通過 onGroupClick()來實現的  
 Gson 框架:
它是谷歌推出的一個請求網絡數據的一個框架,常用的用法如下:  
  1) GSON 的兩個重要方法  
在 GSON 的 API 中,提供了兩個重要的方法:toJson()和 fromJson()方法。其中,toJson()方法  
用來實現將 Java 對象轉換為相應的 JSON 數據,fromJson()方法則用來實現將 JSON 數據轉換為  
相應的 Java 對象。  
  2) toJson()方法,toJson()方法用於將 Java 對象轉換為相應的 JSON 數據,主要有以下幾種形式:  
  String toJson(JsonElement jsonElement);  
  String toJson(Object src);  
  String toJson(Object src, Type typeOfSrc);  
其中,方法(1.1)用於將 JsonElement 對象(可以是 JsonObjectJsonArray 等)轉換成 JSON  
數據;方法(1.2)用於將指定的 Object 對象序列化成相應的 JSON 數據;方法(3)用於將指定  
的 Object 對象(可以包括泛型類型)序列化成相應的 JSON 數據。  
3) 1.2 fromJson()方法  
fromJson()方法用於將 JSON 數據轉換為相應的 Java 對象,主要有以下幾種形式:  
1<T> T fromJson(JsonElement json, Class<T> classOfT);  
2<T> T fromJson(JsonElement json, Type typeOfT);  
3<T> T fromJson(JsonReader reader, Type typeOfT);  
5<T> T fromJson(Reader reader, Type typeOfT);  
6<T> T fromJson(String json, Class<T> classOfT);  
7<T> T fromJson(String json, Type typeOfT);  
以上的方法用於將不同形式的 JSON 數據解析成 Java 對象。  
 
所以說 gson 是一個很好的請求網絡數據的框架,既可以在服務器端生成一個 json 字符串,然后  
客戶端通過發送請求向服務器端,進行數據解析。  
5. Picasso 框架  
  這也是本課程中涉及的一個第三方的框架,它主要是用於網絡請求圖片時的一種框架,它的  
代碼量少,自帶緩存,是一個值得使用的框架。首先 Picasso 也是 Afinal 這個框架的一種,  
Afinal 是一個 android 的 iocorm 框架,內置了四大模塊功能:  
FinalAcitivity,FinalBitmap,FinalDb,FinalHttp。通過 finalActivity,我們可以通過注解的方式進  
行綁定 ui 和事件。通過 finalBitmap,我們可以方便的加載 bitmap 圖片,而無需考慮 oom 等  
問題。通過 finalDB 模塊,我們一行代碼就可以對 android 的 sqlite 數據庫進行增刪改查。通過  
FinalHttp 模塊,我們可以以 ajax 形式請求 http 數據。  

ExpandableListView 和 ExpandableListActivity

如何獲取 ExpandableListView對象
1.可以直接在xml布局中添加 ExpandableListView 在activity中通過id綁定控件
2.activity 繼承 ExpandableListActivity 通過 getExpandableListView 方法獲取

ExpandableListView的常用屬性
android:groupIndicator="" 設置可擴展組圖標提示

點擊事件
  //設置組點擊事件
        //
        melv.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) {
                return false;
            }
        });
        //設置字條目點擊事件
        melv.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView expandableListView, View view, int i, int i1, long l) {
                return false;
            }
        });

 下面進入demo環節

1.實現手風琴效果  獲取本地數據

 效果展示

 

(1).設置xml布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
<ExpandableListView
    android:id="@+id/elv_local"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:groupIndicator="@null"
    android:divider="@null"
    android:dividerHeight="10dp"
    >

</ExpandableListView>

</LinearLayout>

(2).獲取本地數據

//獲取列表組的數據
    public static List<String> getGroupData(){
        List<String> groupList = new ArrayList<>();
        groupList.add("Android課程");
        groupList.add("JAVA課程");
        return groupList;
    }


    //獲取字條目的數據
    public static List<List<String>> getChildData(){
        List<List<String>> childList = new ArrayList<>();
        List<String> item1 = new ArrayList<>();
        item1.add("activity生命周期");
        item1.add("Android 屬性動畫");
        childList.add(item1);
        List<String> item2 = new ArrayList<>();
        item2.add("JAVA集合");
        item2.add("JAVA 多態");
        childList.add(item2);
        return  childList;
    }

(3)配置適配器

package com.example.squeezebox.Adapter;

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

import java.util.List;

/**
 * 適配器封裝
 */
public abstract class MyAdapter extends BaseExpandableListAdapter {
    Context context;
    LayoutInflater minflater;
    public MyAdapter(Context context) {
        this.context = context;
        minflater = LayoutInflater.from(context);
    }
    List<String> group;
    List<List<String>> child;
    public void addNewData(List<String> group,List<List<String>> child){
        this.group = group;
        this.child = child;
    }
    //獲取組的數量
    @Override
    public int getGroupCount() {
        return group.size();
    }
    //獲取字條目的數量
    @Override
    public int getChildrenCount(int i) {
        return child.get(i).size();
    }
    //獲取組的具體的內容
    @Override
    public String getGroup(int i) {
        return group.get(i);
    }
    //獲取字條目具體的內容
    @Override
    public String getChild(int i, int i1) {
        return child.get(i).get(i1);
    }
    //獲取組的id
    @Override
    public long getGroupId(int i) {
        return i;
    }
    //獲取字條目的id
    @Override
    public long getChildId(int i, int i1) {
        return i1;
    }

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

    //可擴展的字條目是否可以被點擊
    @Override
    public boolean isChildSelectable(int i, int i1) {
        return true;
    }

    //獲取組的視圖
    @Override
    public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
        return MyGroupView(i,view);
    }

    //獲取字條目的視圖
    @Override
    public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
        return MyGroupView(i,i1,view);
    }
    public abstract View MyGroupView(int i, View groupView);
    public abstract View MyGroupView(int i, int i1,View childView);

}
package com.example.squeezebox.Adapter;

import android.annotation.SuppressLint;
import android.content.Context;
import android.view.View;
import android.widget.TextView;

import com.example.squeezebox.R;

/**
 * 本地數據適配器
 */
public class LocalAdapter extends MyAdapter {

    public LocalAdapter(Context context) {
        super(context);
    }

    @Override
    public View MyGroupView(int i, View groupView) {
        View view = minflater.inflate(R.layout.group_layout,null);
        TextView textView = view.findViewById(R.id.group_txt);
        textView.setText(getGroup(i));

        textView.setPadding(30,0,0,0);
        return view;
    }


    @Override
    public View MyGroupView(int i, int i1, View childView) {
        View view = minflater.inflate(R.layout.item_layout,null);
        TextView textView = view.findViewById(R.id.item_txt);
        textView.setTextColor(context.getResources().getColor(R.color.steelblue));
        textView.setText(getChild(i,i1));
//        textView.setPadding(30,0,0,0);
        return view;
    }
}

(4)在UI線程中調用

    public void loadLocal(){
        LocalAdapter adapter = new LocalAdapter(this);
        adapter.addNewData(LocalData.getGroupData(),LocalData.getChildData());
        melv.setAdapter(adapter);
    }

2.獲取數據庫數據  使用 CursorTreeAdapter 類

(1) 創建數據庫並建表 以及 添加 查詢方法

public class DBOpenHelper extends SQLiteOpenHelper {
    public DBOpenHelper(Context context) {
        super(context, "hejun.db", null, 1);
    }

    public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, "hejun.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("create table group1(_id integer primary key autoIncrement," +
                "kind text,type text )");
        sqLiteDatabase.execSQL("create table child(_id integer primary key autoIncrement," +
                "kind text,name text,type text )");

    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}
package com.example.squeezebox.DBOpenHelper;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class DBHelp {

    private DBOpenHelper dbOpenHelper;

    public DBHelp(Context context) {
        dbOpenHelper = new DBOpenHelper(context);
    }

    //向組視圖添加數據
    public void insertGroup(String kind, String type) {
        SQLiteDatabase sqLiteDatabase = dbOpenHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("kind",kind);
        values.put("type",type);
        sqLiteDatabase.insert("group1", null, values);
    }

    //查詢組數據
    public Cursor selectGroup() {
        SQLiteDatabase sqLiteDatabase = dbOpenHelper.getReadableDatabase();
        return sqLiteDatabase.query("group1", null, null,null , null, null, null);

    }
    //向字條目添加數據
    public void insertChild(String kind, String leaner,String type) {
        SQLiteDatabase sqLiteDatabase = dbOpenHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("kind", kind);
        values.put("name", leaner);
        values.put("type",type);
        sqLiteDatabase.insert("child", null, values);
    }

    //查詢組數據
    public Cursor selectChild(String type) {
        SQLiteDatabase sqLiteDatabase = dbOpenHelper.getReadableDatabase();
        return sqLiteDatabase.query("child", null, "type=?", new String[]{type}, null, null, null);

    }
}

(2)設置適配器

package com.example.squeezebox.Adapter;

import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorTreeAdapter;
import android.widget.TextView;

import com.example.squeezebox.DBOpenHelper.DBHelp;
import com.example.squeezebox.R;

/**
 * 數據庫適配器
 * cursor  group and child
 */
public class DBAdapter extends CursorTreeAdapter {
    /**
     *
     * @param cursor 組的游標
     * @param context
     */
    DBHelp dbHelp;
    public DBAdapter(Cursor cursor, Context context) {
        super(cursor, context);
        dbHelp = new DBHelp(context);
    }

    //獲取字條目的游標
    @Override
    protected Cursor getChildrenCursor(Cursor cursor) {
        return dbHelp.selectChild(cursor.getString(cursor.getColumnIndex("type")));
    }
    //創建組的視圖
    @Override
    protected View newGroupView(Context context, Cursor cursor, boolean b, ViewGroup viewGroup) {
        View view = LayoutInflater.from(context).inflate(R.layout.group_layout,null);
        return view;
    }
    //綁定組的視圖
    @Override
    protected void bindGroupView(View view, Context context, Cursor cursor, boolean b) {
        TextView textView = view.findViewById(R.id.group_txt);
        textView.setText(cursor.getString(cursor.getColumnIndex("kind")));

    }
    //創建字條目的視圖
    @Override
    protected View newChildView(Context context, Cursor cursor, boolean b, ViewGroup viewGroup) {
        return LayoutInflater.from(context).inflate(R.layout.item2_layout,null);
    }
    //綁定字條目的視圖
    @Override
    protected void bindChildView(View view, Context context, Cursor cursor, boolean b) {
        TextView textView1 = view.findViewById(R.id.item_txt2);
        TextView textView2 = view.findViewById(R.id.item_leaner);
        textView1.setText(cursor.getString(cursor.getColumnIndex("kind")));
        textView2.setText(cursor.getString(cursor.getColumnIndex("name")));
    }
}

(4) 在UI線程調用,插入數據 並為 ExpandableListView 添加Adapter

 public void loadDB(){
        DBHelp db = new DBHelp(this);
        db.insertGroup("Android課程","android");
        db.insertGroup("JAVA課程","java");
        db.insertChild("activity生命周期","1564156","android");
        db.insertChild("Android 屬性動畫","89798","android");
        db.insertChild("JAVA集合","98789","java");
        db.insertChild("JAVA 多態","7988","java");

        Cursor cursor = db.selectGroup();
        DBAdapter dbAdapter = new DBAdapter(cursor,this);
        melv.setAdapter(dbAdapter);
    }

3.獲取網絡數據實現手風琴效果

效果展示:

 

 (1) 異步下載網絡數據,並使用接口回調,傳出數據

package com.example.squeezebox.util;

import android.os.AsyncTask;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class HttpRequest {

    public static void request(String path,onResponseLister onResponseLister){
        new MyAsycnTask(onResponseLister).execute(path);

    }

    static class  MyAsycnTask extends AsyncTask<String,Void,String>{
        private onResponseLister onResponseLister;
        public MyAsycnTask(onResponseLister onResponseLister) {
            this.onResponseLister = onResponseLister;
        }

        @Override
        protected String doInBackground(String... strings) {
            try {
                URL url = new URL(strings[0]);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(5000);
                if (connection.getResponseCode() == HttpURLConnection.HTTP_OK){
                    InputStream in = connection.getInputStream();
                    byte[] bytes = new byte[1024];
                    int len = 0;
                    StringBuilder builder = new StringBuilder();
                    while ((len = in.read(bytes))!= -1){
                        String str = new String(bytes,0,len);
                        builder.append(str);
                    }
                    return builder.toString();
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            if (s != null){
                onResponseLister.onResponseListerSuccess(s);
            }else {
                onResponseLister.onResponseListerSFail("網絡請求錯誤");
            }
        }
    }

    public interface onResponseLister{
        void onResponseListerSuccess(String result);
        void onResponseListerSFail(String result);
    }
}

(2) 解析json數據 創建兩個實體類

public class BaseEntity<T> {

    public String msg;
    public int status;
    public T data;
}
public class Cuesor {
    public String name;
    public String picSmall;
    public String learner;
}
/**
 * 解析數據
 */
public class Parser {

    public static BaseEntity<List<Cuesor>> parserData(String json){
        Gson gson = new Gson();
       return gson.fromJson(json,new TypeToken<BaseEntity<List<Cuesor>>>(){}.getType());
    }
}

(3)配置適配器

package com.example.squeezebox.Adapter;

import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;

import java.util.List;

public abstract class MyBaseAdapter<T> extends BaseExpandableListAdapter {
    Context context;
    LayoutInflater layoutInflater;
    public MyBaseAdapter(Context context) {
        this.context = context;
        layoutInflater = LayoutInflater.from(context);
    }
    private List<String> group;
    private List<List<T>> child;
    public void addNewData(List<String> group, List<List<T>> child){
        this.group =group;
        this.child =child;

    }

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

    @Override
    public int getChildrenCount(int i) {
        return child.get(i).size();
    }

    @Override
    public String getGroup(int i) {
        return group.get(i);
    }

    @Override
    public T getChild(int i, int i1) {
        return child.get(i).get(i1);
    }

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

    @Override
    public long getChildId(int i, int i1) {
        return i1;
    }

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

    @Override
    public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
        return addGroupView(i,view);
    }

    @Override
    public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
        return addChildView(i,i1,view);
    }

    @Override
    public boolean isChildSelectable(int i, int i1) {
        return true;
    }

    public abstract View addGroupView(int i ,View groupView);
    public abstract View addChildView(int i ,int i1,View groupView);
}
package com.example.squeezebox.Adapter;

import android.content.Context;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.squeezebox.R;
import com.example.squeezebox.util.Cuesor;

import it.sephiroth.android.library.picasso.Picasso;

public class NetAdapter extends MyBaseAdapter<Cuesor> {

    public NetAdapter(Context context) {
        super(context);
    }

    @Override
    public View addGroupView(int i, View groupView) {
        TextView textView = new TextView(context);
        textView.setText(getGroup(i));
        return textView;
    }

    @Override
    public View addChildView(int i, int i1, View groupView) {
        View view = layoutInflater.inflate(R.layout.net_item,null);
        ImageView imageView =view.findViewById(R.id.net_img);
        TextView textView1 = view.findViewById(R.id.net_txt1);
        TextView textView2 = view.findViewById(R.id.net_txt2);
        Cuesor cuesor = getChild(i,i1);
        Picasso.with(context).load(cuesor.picSmall).into(imageView);
        textView1.setText(cuesor.name);
        textView2.setText("學習人數:"+cuesor.learner);
        return view;
    }
}

(4) 在UI線程中調用方法並實現接口

   private void loadNet() {
        HttpRequest.request(PATH, new HttpRequest.onResponseLister() {
            @Override
            public void onResponseListerSuccess(String result) {
                BaseEntity<List<Cuesor>> baseEntity = Parser.parserData(result);
                //獲取課程信息
                List<Cuesor> cuesors = baseEntity.data;

                NetAdapter netAdapter = new NetAdapter(MainActivity.this);
                netAdapter.addNewData(LocalData.getGroupData(),LocalData.getNet(cuesors));
                melv.setAdapter(netAdapter);
            }

            @Override
            public void onResponseListerSFail(String result) {

            }
        });
    }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM