2018/10/31

[Android] RecyclerView

如果要寫一個可以滑動的圖片集,Android 有 RecyclerView 這個工具可以用。
這篇就寫簡單基本的用法跟應用。
準備好一些圖片放到專案的drawable資料夾裡 (這邊準備 img_1.png~img_9.png)
首先要先加入所需要的工具,在 app 的 build.gradle 裡面的 dependencies 加入這行:
  1. implementation 'com.android.support:design:26.1.0' // for RecyclerView

在 res/layout 中建立一個要放在RecyclerView裡面的單一物件的 layout.xml
recycler_item.xml:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. android:layout_width="wrap_content"
  5. android:layout_height="wrap_content"
  6. android:orientation="vertical">
  7.  
  8. <ImageView
  9. android:id="@+id/id_ivItem"
  10. android:layout_width="200dp"
  11. android:layout_height="200dp"
  12. android:layout_marginEnd="8dp"
  13. android:layout_marginStart="8dp"
  14. android:src="@drawable/img_1"
  15. app:layout_constraintEnd_toEndOf="parent"
  16. app:layout_constraintStart_toStartOf="parent"
  17. app:layout_constraintTop_toTopOf="parent" />
  18.  
  19. </android.support.constraint.ConstraintLayout>

接著在專案java資料夾中建立一個 class 來處理RecyclerView的一些細節設計
RecyclerMainAdapter.java:
  1. public class RecyclerMainAdapter extends RecyclerView.Adapter{
  2. private String TAG = "RecyclerMainAdapter";
  3. private List mData;
  4. class ViewHolder extends RecyclerView.ViewHolder {
  5. ImageView mImageView;
  6. ViewHolder(View v) {
  7. super(v);
  8. // find item view
  9. mImageView = (ImageView)v.findViewById(R.id.id_ivItem);
  10. }
  11. }
  12. RecyclerMainAdapter(List data) {
  13. mData = data;
  14. }
  15. @Override
  16. public RecyclerMainAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  17. View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
  18. return new ViewHolder(v);
  19. }
  20. @Override
  21. public void onBindViewHolder(final RecyclerMainAdapter.ViewHolder holder, final int position) {
  22. // set the image from imgUrls by position
  23. for(int i = 0; i < MainActivity.imgArray.length; i++){
  24. if(position == i){
  25. holder.mImageView.setImageResource(MainActivity.imgArray[i]);
  26. }
  27. }
  28. }
  29. @Override
  30. public int getItemCount() {
  31. return mData.size();
  32. }
  33. }

在 onBindViewHolder 中可以設定每個 item 的圖片來源,這邊是抓 MainActivity 的 imgArray 陣列已經存好的圖檔路徑。

另外,如果要針對每個 item 加入 click 事件的話,可以在 onBindViewHolder 裡面加入:
  1. // set onclick listener on recyclerView
  2. holder.mImageView.setOnClickListener(new View.OnClickListener() {
  3. @Override
  4. public void onClick(View v) {
  5. Log.d(TAG, "onClick " + position);
  6. }
  7. });

在主要layout中加入RecyclerView物件
activity_main.xml:
  1. <android.support.v7.widget.RecyclerView
  2. android:id="@+id/id_rv"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content"/>

最後加入主程式碼
MainActivity.java
  1. public class MainActivity extends AppCompatActivity{
  2.  
  3. private String TAG = "MainActivity";
  4.  
  5. public static int imgArray[] = {
  6. R.drawable.img_1, R.drawable.img_2, R.drawable.img_3,
  7. R.drawable.img_4, R.drawable.img_5, R.drawable.img_6,
  8. R.drawable.img_7, R.drawable.img_8, R.drawable.img_9};
  9.  
  10. private RecyclerView mRecyclerView;
  11.  
  12. @Override
  13. protected void onCreate(Bundle savedInstanceState) {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.activity_main);
  16.  
  17. mRecyclerView = findViewById(R.id.id_rv);
  18.  
  19. // init recyclerView
  20. InitRecyclerView();
  21. }
  22.  
  23. private void InitRecyclerView(){
  24. ArrayList myDataset = new ArrayList<>();
  25. for(int i = 0; i < imgArray.length; i++){
  26. myDataset.add(Integer.toString(i));
  27. }
  28. // set layout for recyclerview
  29. final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
  30. layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // set HORIZONTAL or VERTICAL
  31. // set cover adapter and recyclerview
  32. RecyclerMainAdapter mRecyclerMainAdapter = new RecyclerMainAdapter(myDataset);
  33. mRecyclerView.setLayoutManager(layoutManager);
  34. mRecyclerView.setAdapter(mRecyclerMainAdapter);
  35. }
  36. }

程式執行後就能看到一個滑動的圖片集了。
在這行可以設定RecyclerView的垂直或水平方向:
  1. layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // set HORIZONTAL or VERTICAL

如果放開 RecyclerView 的時候,想要讓圖片每次自動固定在中間,可以加入:
  1. // set snap on recyclerview
  2. final SnapHelper helper = new LinearSnapHelper();
  3. helper.attachToRecyclerView(mRecyclerView);

如果想要知道目前滑到哪一個 item,則可以加入:
  1. // get current position from recycleView
  2. mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
  3. @Override
  4. public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
  5. super.onScrollStateChanged(recyclerView, newState);
  6.  
  7. if(newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
  8. View centerView = helper.findSnapView(layoutManager);
  9. int pos = 0;
  10. if (centerView != null) {
  11. pos = layoutManager.getPosition(centerView);
  12. Log.d(TAG, "RecyclerView: " + pos);
  13. }
  14. }
  15. }
  16. });

其中 pos 就是目前滑到的 item。

另外,如果要直接跳到某個 item 的話,例如要跳到第二個 item 則可以用:
  1. // jump to certain position
  2. mRecyclerView.smoothScrollToPosition(2);

做完之後發現 RecyclerView 滑到底的時候,邊邊會跑出一個半透明的提示圖案。
只要加一行到 activity_main.xml 裡面的 RecyclerView 物件就好了:
  1. android:overScrollMode="never"

這邊有碰到一個小問題就是,當滑到第一個跟最後一個 item 會沒辦法置中,
一個簡單的解法就是在第一個跟最後一個用透明圖檔的 item 來當作緩衝。
  1. public static int imgArray[] = {
  2. R.drawable.transparent,
  3. R.drawable.img_1, R.drawable.img_2, R.drawable.img_3,
  4. R.drawable.img_4, R.drawable.img_5, R.drawable.img_6,
  5. R.drawable.img_7, R.drawable.img_8, R.drawable.img_9,
  6. R.drawable.transparent};

然後在 mRecyclerView.addOnScrollListener 的 onScrollStateChanged 裡面加入判斷,
當滑到第一個或最後一個時,會往後或往前推一下
  1. // get current position from recycleView
  2. mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
  3. @Override
  4. public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
  5. super.onScrollStateChanged(recyclerView, newState);
  6. if(newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
  7. View centerView = helper.findSnapView(layoutManager);
  8. int pos = 0;
  9. if (centerView != null) {
  10. pos = layoutManager.getPosition(centerView);
  11. Log.d(TAG, "RecyclerView: " + pos);
  12. }
  13.  
  14. // block first and last space
  15. if(pos == 0){
  16. mRecyclerView.smoothScrollToPosition(1);
  17. }
  18. else if(pos == imgArray.length - 1){
  19. mRecyclerView.smoothScrollToPosition(imgArray.length - 2);
  20. }
  21. }
  22. }
  23. });

END

沒有留言:

張貼留言