今天要來聊的又是RecyclerView (・∀・)(・∀・)(・∀・)

RecyclerView本網誌截至今天是第五篇

一樣先把我所有寫過的RecyclerView連結貼上來吧

 

碼農日常-『Android studio』基本RecyclerView用法

碼農日常-『Android studio』基本RecyclerView 用法-2 基本版下拉更新以及點擊事件

碼農日常-『Android studio』基本RecyclerView 用法-3 RecyclerView上下滑動排序與側滑刪除(RecyclerView Swipe)

碼農日常-『Android studio』基本RecyclerView 用法-4 左滑顯示Button Menu

 

今天要寫的內容我把它叫做"RecyclerView 混合介面/佈局"

當初我在找資料的時候是用中文搜尋到的

也在這邊放上參考資料

->https://www.jianshu.com/p/c9ce1c67981d

這篇的搜尋結果在Google排名上是前幾的,應該很容易可以搜尋到

keyWord:RecyclerView混合佈局

 

簡單來說今天的內容就是要在一個RecyclerView裡面加入兩種(以上)的佈局

像這樣

Screenshot_20200530-141634_RecyclerViewMixitemExample

不用懷疑,這是只用一個RecyclerView做出來的哦(・ω・)b

那兩個介面在哪裡呢?

個介面就是標題A、B、C的那個部分

而第個介面是顯示英文單字以及翻譯按鈕的那個介面

 

那麽理解了今天要講的內容的話,就來上今天的Gif功能吧

RecyclerView混合介面

 

以及Github

->https://github.com/thumbb13555/RecyclerViewMixitemExample

 

開始~


 

1.先建立好所有需要的介面&類別

不知有否注意到今天的標題?

"碼農日常-『Android studio』進階RecyclerView 用法-5 RecyclerView item混合介面"

這次的標題,我不再寫"基本"而是"進階"(・ωー)~☆

主要原因很簡單,因為這次的內容不是一個類別可以完成的內容

而我在撰寫的過程中,也是用較貼近平常工作的寫法下去寫

希望不會對你造成太多的不適應QQ(當然,我也會很努力地讓你就算不理解也能實作出來)

那就真正開始今天要做的內容吧(•ө•)♡

1-1. 建立介面

今天要建立三個介面,分別如下

1. activity_main.xml

2. a_type_item.xml

3. b_type_item.xml

截圖 2020-05-30 下午3.47.30

activity_main 就是主要畫面的RecyclerView

a_type_item 則是RecyclerView的第一種介面

b_type_item 則是RecyclerView的第二種介面

 

會來看這篇文的應該都應該不是新手,建立介面過程省略啦wwwww

那就奉上這三個介面吧

 

activity_main.xml

截圖 2020-05-30 下午3.56.17

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

a_type_item.xml

截圖 2020-05-30 下午3.56.22

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

b_type_item.xml

截圖 2020-05-30 下午3.56.30

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/textView_Word"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:text="TextView"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button_GetChinese"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="16dp"
        android:text="顯示中文"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

1-2. 建立所需的類別

接下來就是類別了,我直接先給各位看看所有的類別吧

截圖 2020-05-30 下午4.05.09

截圖 2020-05-30 下午4.05.33

 

其中MyViewHolders、A_TypeMyView、B_TypeMyView都是給item介面用的

其中以上所有類別之間的關係為

截圖 2020-05-30 下午2.46.18

 

在這邊建議如果是完全不會的朋友,想要模仿我做的內容

可以先照著我圖片中的類別先建立起來,然後接下來就一個一個講


 

2.撰寫功能

齁...要來撰寫功能了(吸氣...)

首先要先來寫MainActivity的部分(`・ω・´)+

其中我有製作一些單字用的資料,如何寫的不是重點(當然我會PO)

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        /**設置recyclerView有分隔線*/
        recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
        MyRecyclerViewAdapter mAdapter = new MyRecyclerViewAdapter(makeData());
        recyclerView.setAdapter(mAdapter);   
    }
    /**製作單字資料*/
    private ArrayList<HashMap<String,String>> makeData(){
        ArrayList<HashMap<String,String>> arrayList = new ArrayList<>();
        String[] vocabulary = {"#A","aptitude","apprentice"
                ,"#B","bilingual","banquet"
                ,"#C","credential","coordinator","contain","continued"
                ,"#D","distributor","deviate"
                ,"#E","enhancement","election","engrave","excess"
                ,"#F","factor"};
        String[] chinese = {"#A","才能、資質","實習生"
                ,"#B","雙語的","宴會"
                ,"#C","證書","協調者","包含","持續的"
                ,"#D","分配者、分銷商","偏離"
                ,"#E"," 提升、改善","選舉","雕刻","超量"
                ,"#F","要素"};
        for (int i = 0; i < vocabulary.length; i++) {
            HashMap<String,String> hashMap = new HashMap<>();
            if (vocabulary[i].charAt(0) == '#'){
                hashMap.put("ENGLISH",vocabulary[i].replace("#",""));
                hashMap.put("CHINESE","--");
                hashMap.put("VIEW_TYPE","0");
            }else{
                hashMap.put("ENGLISH",vocabulary[i]);
                hashMap.put("CHINESE",chinese[i]);
                hashMap.put("VIEW_TYPE","1");
            }
            arrayList.add(hashMap);
        }
        return arrayList;
    }//makeData
}

這時候,如果你檢視一下輸出的內容,大概就是長這樣:

截圖 2020-05-30 下午1.30.59

再來,來到MyRecyclerViewAdapter.java

class MyRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private ArrayList<HashMap<String,String>> arrayList;
    public OnTransClick onItemClick;
    public MyRecyclerViewAdapter(ArrayList<HashMap<String,String>> arrayList) {
        this.arrayList = arrayList;
    }
    /**設置將資料傳回Activity的接口*/
    public void setOnTransButtonClick(OnTransClick onItemClick){
        this.onItemClick = onItemClick;
    }
    /**取得每個item內的"VIEW_TYPE"*/
    @Override
    public int getItemViewType(int position) {
        int getType = Integer.parseInt(arrayList.get(position).get("VIEW_TYPE"));
        return getType;
    }
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        /**在上面的"getItemViewType"中取得的
         * @see viewType
         * 為基準,判斷每個item需使用哪個介面*/
        if (viewType == 1) {
            return new B_TypeMyView(LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.b_type_item, parent, false));
        } else {
            return new A_TypeMyView(LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.a_type_item, parent, false));
        }
    }
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        /**將holder強制轉型為"MyViewHolders"類別,使介面A/B都可以獲得onBindViewHolder內容*/
        ((MyViewHolders) holder).bindViewHolder(arrayList.get(position));      
    }
    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    /**設置點擊方法,使點擊後取得到的內容能傳回MainActivity*/
    public interface OnTransClick{
        void OnTransButtonClick(HashMap<String,String> hashMap);
    }
}

 

關鍵點是在粉底的部分

那個類別叫做getItemViewType,回傳的值會出現在onCreateViewHolderviewType內(綠底)

而其中getItemViewType可以理解為他會幫你跑一次你所輸入的陣列,因此可以偵測到你所輸入的判斷依據

再仔細回頭看我們前面PO過的資料輸出

截圖 2020-05-30 下午1.30.59 2

 

這樣大致可以理解了嗎?(¬_¬)ノ

這時候你會發現綠底的部分會出錯

是因為我們沒有寫三個介面的內容~

所以以下直接寫MyViewHolders、A_TypeMyView、B_TypeMyView

 

MyViewHolders

public abstract class MyViewHolders extends RecyclerView.ViewHolder {
    public MyViewHolders(@NonNull View itemView) {
        super(itemView);
    }
    /**建立抽象類別,並使onBindViewHolder可分別綁定到介面A與介面B*/
    public abstract void bindViewHolder(HashMap<String,String> hashMap);
}

 

A_TypeMyView

public class A_TypeMyView extends MyViewHolders {
    public TextView tvTitle;

    public A_TypeMyView(@NonNull View itemView) {
        super(itemView);
        tvTitle = itemView.findViewById(R.id.textView_ATItle);

    }
    /**將資料綁到介面A的內容*/
    @Override
    public void bindViewHolder(HashMap<String, String> hashMap) {
        tvTitle.setText(hashMap.get("ENGLISH"));
    }
}

 

B_TypeMyView

public class B_TypeMyView extends MyViewHolders {

    public Button btTrans;
    public TextView tvShow;

    public B_TypeMyView(@NonNull View itemView) {
        super(itemView);
        btTrans = itemView.findViewById(R.id.button_GetChinese);
        tvShow = itemView.findViewById(R.id.textView_Word);
    }
    /**將資料綁到介面B的內容*/
    @Override
    public void bindViewHolder(HashMap<String, String> hashMap) {
        tvShow.setText(hashMap.get("ENGLISH"));
    }
}

 

好,這時候可以試者執行一下

Screenshot_20200530-141634_RecyclerViewMixitemExample

 

這時候就可以看到基本介面囉d(>_・ )

 


 

3.撰寫點擊事件

這次要設置點擊事件了

其實我都已經把點擊該做的事都寫好了XD

其主要的內容主要寫在MyRecyclerViewAdapterMainActivity

那我就來標注一下MyRecyclerViewAdapter的點擊相關吧

class MyRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private ArrayList<HashMap<String,String>> arrayList;
    public OnTransClick onItemClick;
    public MyRecyclerViewAdapter(ArrayList<HashMap<String,String>> arrayList) {
        this.arrayList = arrayList;
    }
    /**設置將資料傳回Activity的接口*/
    public void setOnTransButtonClick(OnTransClick onItemClick){
        this.onItemClick = onItemClick;
    }
    /**取得每個item內的"VIEW_TYPE"*/
    @Override
    public int getItemViewType(int position) {
        int getType = Integer.parseInt(arrayList.get(position).get("VIEW_TYPE"));
        return getType;
    }
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        /**在上面的"getItemViewType"中取得的
         * @see viewType
         * 為基準,判斷每個item需使用哪個介面*/
        if (viewType == 1) {
            return new B_TypeMyView(LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.b_type_item, parent, false));
        } else {
            return new A_TypeMyView(LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.a_type_item, parent, false));
        }
    }
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        /**將holder強制轉型為"MyViewHolders"類別,使介面A/B都可以獲得onBindViewHolder內容*/
        ((MyViewHolders) holder).bindViewHolder(arrayList.get(position));
        /**判斷該item的介面是處於哪一個介面*/
        if (holder instanceof A_TypeMyView){
            //你可以試著為他加入點擊事件~
        }else if (holder instanceof B_TypeMyView){
            B_TypeMyView bTypeMyView = (B_TypeMyView) holder;
            /**設置翻譯按鈕的點擊事件*/
            bTypeMyView.btTrans.setOnClickListener(v->{
                onItemClick.OnTransButtonClick(arrayList.get(position));
            });
        }
    }
    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    /**設置點擊方法,使點擊後取得到的內容能傳回MainActivity*/
    public interface OnTransClick{
        void OnTransButtonClick(HashMap<String,String> hashMap);
    }
}

 

最後,將資訊傳至MainActivity吧(此處為MainActivity.java)

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

    RecyclerView recyclerView = findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    /**設置recyclerView有分隔線*/
    recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
    MyRecyclerViewAdapter mAdapter = new MyRecyclerViewAdapter(makeData());
    recyclerView.setAdapter(mAdapter);
    /**從MyRecyclerViewAdapter取得資料的點擊事件*/
    mAdapter.setOnTransButtonClick(hashMap -> {
        String getTrans = hashMap.get("CHINESE");
        Toast.makeText(this, getTrans, Toast.LENGTH_SHORT).show();
    });//Click
}

這時候按下執行,就可以看到想要的內容囉

RecyclerView混合介面

Screenshot_20200530-141746_RecyclerViewMixitemExample

 

 


 

最後放上所有的類別吧!

截圖 2020-05-30 下午4.05.33


 

MainActivity.java

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        /**設置recyclerView有分隔線*/
        recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
        MyRecyclerViewAdapter mAdapter = new MyRecyclerViewAdapter(makeData());
        recyclerView.setAdapter(mAdapter);
        /**從MyRecyclerViewAdapter取得資料的點擊事件*/
        mAdapter.setOnTransButtonClick(hashMap -> {
            String getTrans = hashMap.get("CHINESE");
            Toast.makeText(this, getTrans, Toast.LENGTH_SHORT).show();
        });//Click
    }
    /**製作單字資料*/
    private ArrayList<HashMap<String,String>> makeData(){
        ArrayList<HashMap<String,String>> arrayList = new ArrayList<>();
        String[] vocabulary = {"#A","aptitude","apprentice"
                ,"#B","bilingual","banquet"
                ,"#C","credential","coordinator","contain","continued"
                ,"#D","distributor","deviate"
                ,"#E","enhancement","election","engrave","excess"
                ,"#F","factor"};
        String[] chinese = {"#A","才能、資質","實習生"
                ,"#B","雙語的","宴會"
                ,"#C","證書","協調者","包含","持續的"
                ,"#D","分配者、分銷商","偏離"
                ,"#E"," 提升、改善","選舉","雕刻","超量"
                ,"#F","要素"};
        for (int i = 0; i < vocabulary.length; i++) {
            HashMap<String,String> hashMap = new HashMap<>();
            if (vocabulary[i].charAt(0) == '#'){
                hashMap.put("ENGLISH",vocabulary[i].replace("#",""));
                hashMap.put("CHINESE","--");
                hashMap.put("VIEW_TYPE","0");
            }else{
                hashMap.put("ENGLISH",vocabulary[i]);
                hashMap.put("CHINESE",chinese[i]);
                hashMap.put("VIEW_TYPE","1");
            }
            arrayList.add(hashMap);
        }
        return arrayList;
    }//makeData
}

 

MyRecyclerViewAdapter.java

class MyRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private ArrayList<HashMap<String,String>> arrayList;
    public OnTransClick onItemClick;
    public MyRecyclerViewAdapter(ArrayList<HashMap<String,String>> arrayList) {
        this.arrayList = arrayList;
    }
    /**設置將資料傳回Activity的接口*/
    public void setOnTransButtonClick(OnTransClick onItemClick){
        this.onItemClick = onItemClick;
    }
    /**取得每個item內的"VIEW_TYPE"*/
    @Override
    public int getItemViewType(int position) {
        int getType = Integer.parseInt(arrayList.get(position).get("VIEW_TYPE"));
        return getType;
    }
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        /**在上面的"getItemViewType"中取得的
         * @see viewType
         * 為基準,判斷每個item需使用哪個介面*/
        if (viewType == 1) {
            return new B_TypeMyView(LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.b_type_item, parent, false));
        } else {
            return new A_TypeMyView(LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.a_type_item, parent, false));
        }
    }
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        /**將holder強制轉型為"MyViewHolders"類別,使介面A/B都可以獲得onBindViewHolder內容*/
        ((MyViewHolders) holder).bindViewHolder(arrayList.get(position));
        /**判斷該item的介面是處於哪一個介面*/
        if (holder instanceof A_TypeMyView){
            //你可以試著為他加入點擊事件~
        }else if (holder instanceof B_TypeMyView){
            B_TypeMyView bTypeMyView = (B_TypeMyView) holder;
            /**設置翻譯按鈕的點擊事件*/
            bTypeMyView.btTrans.setOnClickListener(v->{
                onItemClick.OnTransButtonClick(arrayList.get(position));
            });
        }
    }
    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    /**設置點擊方法,使點擊後取得到的內容能傳回MainActivity*/
    public interface OnTransClick{
        void OnTransButtonClick(HashMap<String,String> hashMap);
    }
}

 

MyViewHolders.java

public abstract class MyViewHolders extends RecyclerView.ViewHolder {
    public MyViewHolders(@NonNull View itemView) {
        super(itemView);
    }
    /**建立抽象類別,並使onBindViewHolder可分別綁定到介面A與介面B*/
    public abstract void bindViewHolder(HashMap<String,String> hashMap);
}

 

A_TypeMyView

public class A_TypeMyView extends MyViewHolders {
    public TextView tvTitle;

    public A_TypeMyView(@NonNull View itemView) {
        super(itemView);
        tvTitle = itemView.findViewById(R.id.textView_ATItle);

    }
    /**將資料綁到介面A的內容*/
    @Override
    public void bindViewHolder(HashMap<String, String> hashMap) {
        tvTitle.setText(hashMap.get("ENGLISH"));
    }
}

 

B_TypeMyView

public class B_TypeMyView extends MyViewHolders {

    public Button btTrans;
    public TextView tvShow;

    public B_TypeMyView(@NonNull View itemView) {
        super(itemView);
        btTrans = itemView.findViewById(R.id.button_GetChinese);
        tvShow = itemView.findViewById(R.id.textView_Word);
    }
    /**將資料綁到介面B的內容*/
    @Override
    public void bindViewHolder(HashMap<String, String> hashMap) {
        tvShow.setText(hashMap.get("ENGLISH"));
    }
}

 


 

 

結語

前面也說了,今天的內容是比較進階的的內容

今天之所以會寫這個,是因為我之前在找這方面的資料的時候

實在是非常不滿我們台灣沒有人寫這方面的資料,我真的覺得非常可惜OTL((也許有啦,只是沒找到

唉...有時候真的很感慨,大陸就是人多,所以技術文章也多

台灣最近有出了個IT邦,但是畢竟歷史不夠久,人口基數也不夠多

所以技術文章的廣度跟深度還是有限,真的很可惜(´υ`)

 

那麼希望今天的這篇文章可以幫助到你,祝各位程式沒有Bug

下載

arrow
arrow

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