1. 程式人生 > >Android Widget:RecyclerView (一)

Android Widget:RecyclerView (一)

RecyclerView的基本操作

我也不曉得為何第一個GIF花屏了,我用AS的AVD錄屏的,播放完好,覺得是CS/DN的鍋

列表展示
Fruits

訊息列表
聊天介面


RecyclerView的使用

RecyclerView通過LinearLayoutManager和Adapter來管理佈局和適配View中的每一個子項

大致分為五個步驟


新增RecyclerView支援

在app目錄下的build.gradle的dependencies中新增implementation ‘com.android.support:recyclerview-v7:25.3.1’

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    implementation 'com.android.support:recyclerview-v7:25.3.1'//可以到SDK目錄下extras\android\m2repository\com\android\support中檢視版本填寫版本號
testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' }

同步後即可使用該控制元件


RecyclerView的使用
這裡給出圖一的Fruit實現程式碼

首先根據子項item期望的顯示方式建立佈局檔案
圖中的佈局檔案如下

//fruit_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/fruit_image" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/fruit_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textSize="20dp" android:layout_marginStart="10dp" /> </LinearLayout>

建立Fruit類

//Fruit.java
public class Fruit {
    private String name;
    private int imageId;

    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}

建立介面卡FruitAdapter類

程式碼詳解已在註釋中

//FruitAdapter.java

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
//FruitAdapter繼承自RecyclerView.Adapter並規定是配的型別為FruitAdapter.ViewHolder

    private List<Fruit> mFruitList;//資料來源,所有Fruit都引用到這裡去適配

    public FruitAdapter(List<Fruit> mFruitList) {
        this.mFruitList = mFruitList;
    }


    static class ViewHolder extends RecyclerView.ViewHolder {

//FruitAdapter類中定義的靜態內部類,繼承自RecyclerView.ViewHolder
        private ImageView fruitImage;
        private TextView fruitName;//每個ViewHolder物件要儲存的控制元件
        public ViewHolder(View itemView) {
            super(itemView);
            fruitImage = itemView.findViewById(R.id.fruit_image);//定位到fruit_item中的ImageView
            fruitName = itemView.findViewById(R.id.fruit_name);//定位到fruit_item中的TextView
        }
    }

    @Override
    public FruitAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.fruit_item,parent,false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }
    //渲染item的View並製造ViewHolder的物件儲存該View
//LayoutInflater.from(Context context)從一個Context中,獲得一個佈局填充器,inflate(int R.layout.xml,ViewGroup root,boolean attachToRoot)使用這個填充器按照xml佈局檔案填充一個佈局/View物件
//引數說明     稍後詳解
//R.layout.xml   期望的item佈局檔案
//ViewGroup root 根佈局  依照該佈局填充出View ViewGroup的繼承關係: View -> ViewGroup -> Layout
//boolean attachToRoot attachToRoot為true的情況下,這個佈局會被解析並載入到root
//如果為false,則會依照root去解析該xml並返回該佈局


//ViewHolder  顧名思義,用作儲存View   即快取製造的View,通過複用減少View的重複建立,提高效率

    @Override
    public void onBindViewHolder(FruitAdapter.ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }//將每個ViewHolder中的View指定到具體資源

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }//返回資料來源的大小/item的個數

}


在Activity中使用

//MainActivity.java

public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.module_main_activity);
        initializeFruits();
        RecyclerView recyclerView = findViewById(R.id.rv_fruitList);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);//佈局管理器
        recyclerView.setLayoutManager(linearLayoutManager);//指定佈局管理器
        FruitAdapter adapter = new FruitAdapter(fruitList);//介面卡
        recyclerView.setAdapter(adapter);//指定介面卡
    }

    private void initializeFruits(){//初始化資料
        for(int i = 1;i<=2;i++){
            fruitList.add(new Fruit("apple",R.drawable.apple_pic));
            fruitList.add(new Fruit("banana",R.drawable.banana_pic));
            fruitList.add(new Fruit("orange",R.drawable.orange_pic));
            fruitList.add(new Fruit("watermelon",R.drawable.watermelon_pic));
            fruitList.add(new Fruit("pear",R.drawable.pear_pic));
            fruitList.add(new Fruit("grape",R.drawable.grape_pic));
            fruitList.add(new Fruit("pineapple",R.drawable.pineapple_pic));
            fruitList.add(new Fruit("strawberry",R.drawable.strawberry_pic));
            fruitList.add(new Fruit("cherry",R.drawable.cherry_pic));
            fruitList.add(new Fruit("mango",R.drawable.mango_pic));
        }
    }

}
//over

RecyclerView的使用注意

  • 資料缺失、遺漏
//      在介面卡中重寫getItemViewType方法
        @Override public int getItemViewType(int position) { return position; }

//      禁止ViewHolder複用      (降低效率   不推薦)
//      在onCreateViewHolder製造出ViewHolder後
        holder.setIsRecyclable(false);

  • 引入支援時的版本問題
代號 含義
Alpha (α) 預覽版
Beta (β) 測試版
RC (Release Candidate) 最終測試版本

越往下越穩定
若出現版本不一致問題
可在app下的build.gradle中新增

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == 'com.android.support') {
            if (!requested.name.startsWith("multidex")) {
                details.useVersion '25.3.1'//指定版本號
            }
        }
    }
}

onCreateViewHolder詳解 //初學者瞭解

  • root為null,attachToRoot將失效
  • root不為null,若attachToRoot設定為為true,則會給載入的佈局檔案的指定一個父佈局,即root;若attachToRoot設為false,則會將佈局檔案最外層的所有layout屬性進行設定,當該view被新增到父view當中時,這些layout屬性會自動生效
  • root不為null時,attachToRoot引數預設為true

返回的view是父容器佈局(不是item佈局的根容器,如例中的root佈局)
item根佈局的寬高屬性生效(item佈局的根容器寬高屬性生效)
新增到父容器中(item佈局已經新增到root中了)

RelativeLayout root = (RelativeLayout) findViewById(R.id.other_layout);
View view = LayoutInflater.from(this).inflate(R.layout.item, root, true);
View view = LayoutInflater.from(this).inflate(R.layout.item, root);

返回R.layout.item頁面的根佈局(item根佈局)
根佈局的寬高屬性生效
未新增到父容器中

RelativeLayout root = (RelativeLayout) findViewById(R.id.other_layout);
View view1 = LayoutInflater.from(this).inflate(R.layout.item, root, false);

返回R.layout.item頁面的根佈局
根佈局的寬高屬性失效(僅寬高屬性失效,其他屬性生效)
未新增到父容器中

View view3 = LayoutInflater.from(this).inflate(R.layout.item, null, false);
View view4 = LayoutInflater.from(this).inflate(R.layout.item, null, true);
View view6 = LayoutInflater.from(this).inflate(R.layout.item, null);


2018/8/15