Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 【FastDev4Android框架開發】RecyclerView完全解析之打造新版類Gallery效果(二十九)

【FastDev4Android框架開發】RecyclerView完全解析之打造新版類Gallery效果(二十九)

編輯:關於Android編程

 

(一).前言:

話說RecyclerView已經面市很久,也在很多應用中得到廣泛的使用,在整個開發者圈子裡面也擁有很不錯的口碑,那說明RecyclerView擁有比ListView,GridView之類控件有很多的優點,例如:數據綁定,Item View創建,View的回收以及重用等機制。本系列文章會包括到以下三個部分:

  1. RecyclerView控件的基本使用,包括基礎,進階,高級部分,動畫之類(點擊進入)
  2. RecyclerView控件的實戰實例
  3. RecyclerView控件集合AA(Android Annotations)注入框架實例

    今天使我們本系列文章的第二講主要是我們通過RecyclerView來打造一個新版類似Gallery控件的效果。本次講解所有用的Demo例子已經全部更新到下面的項目中了,歡迎大家star和fork。

    FastDev4Android框架項目地址:https://github.com/jiangqqlmj/FastDev4Android

    (二).基本實現

    上一講我們已經對於RecyclerView的基本使用和進階部分做了講解(點擊進入),下面我們一步步的來打造一個新版Gallery效果控件。先來看一下和RecyclerView相關類:

    類名

    說明

    RecyclerView.Adapter

    可以托管數據集合,為每一項Item創建視圖並且綁定數據

    RecyclerView.ViewHolder

    承載Item視圖的子布局

    RecyclerView.LayoutManager

    負責Item視圖的布局的顯示管理

    RecyclerView.ItemDecoration

    給每一項Item視圖添加子View,可以進行畫分隔線之類的東西

    RecyclerView.ItemAnimator

    負責處理數據添加或者刪除時候的動畫效果

    那如果要實現Gallery的效果,裡面的Item是橫向滑動的,也就是說我們的RecyclerView可以支持橫向滑動,這邊我們直接采用了LinearLayoutManager布局管理器,同時設置方向為:HORIZONTAL(水平)

    下面來具體看代碼:

    1.作為RecyclerView控件,我們需要設置每一項Item的布局:

     

    
    
        
        
    

     

    這個布局中我們比較簡單,定義了一個圖片和一個標題,垂直方向布局。

    2.間接著,和ListView寫法差不多,需要自定義適配器,來創建每一項布局視圖以及把數據和視圖綁定起來,所以這邊繼承RecyclerView.Adapter類創建一個自定義適配器GalleryRecyclerAdapter.java。那麼需要實現基類中的三個方法:

    • onCreateViewHolder(ViewGroup parent,int viewType) 創建Item View然後通過ViewHolder來承載
    • onBindViewHolder(ViewHolder holder,int position)進行視圖和數據綁定
    • getItemCount()獲取列表中視圖Item的數量

      具體GallerRecyclerAdapter實現代碼如下:

       

      public class GalleryRecyclerAdapter extends RecyclerView.Adapter {
       
          private List models;
          private LayoutInflater mInflater;
       
          public GalleryRecyclerAdapter(Context context){
              models=new ArrayList();
              for (int i=0;i<20;i++){
                  int index=i+1;
                  models.add(new GalleryModel(R.drawable.ic_item_gallery,Item+index));
              }
              mInflater=LayoutInflater.from(context);
          }
       
          /**
           * 創建Item View  然後使用ViewHolder來進行承載
           * @param parent
           * @param viewType
           * @return
           */
          @Override
          public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
              View view=mInflater.inflate(R.layout.item_gallery_recycler,parent,false);
              ViewHolder viewHolder=new ViewHolder(view);
              return viewHolder;
          }
       
          /**
           * 進行綁定數據
           * @param holder
           * @param position
           */
          @Override
          public void onBindViewHolder(ViewHolder holder, int position) {
             holder.item_img.setImageResource(models.get(position).getImgurl());
             holder.item_tv.setText(models.get(position).getTitle());
          }
       
          @Override
          public int getItemCount() {
              return models.size();
          }
       
       
          //自定義的ViewHolder,持有每個Item的的所有界面元素
          public static class ViewHolder extends RecyclerView.ViewHolder {
              private ImageView item_img;
              private TextView item_tv;
              public ViewHolder(View view){
                  super(view);
                 item_img=(ImageView)view.findViewById(R.id.item_img);
                 item_tv=(TextView)view.findViewById(R.id.item_tv);
              }
          }
       
      }

       

      3.注意看上面的代碼,我們繼承了RecyclerView.ViewHolder實現一個自定義類ViewHolder,這個用來承載我們的子Item視圖,現在Google已經要求開發者必須要使用ViewHolder了。在ViewHolder中我們進行控件的初始化工作,然後保存View視圖。

       

      //自定義的ViewHolder,持有每個Item的的所有界面元素
          public static class ViewHolder extends RecyclerView.ViewHolder {
              private ImageView item_img;
              private TextView item_tv;
              public ViewHolder(View view){
                  super(view);
                 item_img=(ImageView)view.findViewById(R.id.item_img);
                 item_tv=(TextView)view.findViewById(R.id.item_tv);
              }
          }

       

      4.最後在Activity中控件設置,例如布局管理器,Adapter綁定即可,完整代碼如下:

       

      public class RecyclerGalleryActivity extends BaseActivity {
          private RecyclerView gallery_recycler;
          private LinearLayout top_bar_linear_back;
          private TextView top_bar_title;
          @Override
          protected void onCreate(BundlesavedInstanceState) {
              super.onCreate(savedInstanceState);
             setContentView(R.layout.recycler_gallery_layout);
             top_bar_linear_back=(LinearLayout)this.findViewById(R.id.top_bar_linear_back);
             top_bar_linear_back.setOnClickListener(new CustomOnClickListener());
             top_bar_title=(TextView)this.findViewById(R.id.top_bar_title);
             top_bar_title.setText(RecyclerView打造Gallery效果);
              //初始化RecyclerView控件
             gallery_recycler=(RecyclerView)this.findViewById(R.id.gallery_recycler);
              //固定高度
              gallery_recycler.setHasFixedSize(true);
              //創建布局管理器
              LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
              //設置橫向
             linearLayoutManager.setOrientation(OrientationHelper.HORIZONTAL);
              //設置布局管理器
             gallery_recycler.setLayoutManager(linearLayoutManager);
              //創建適配器
              GalleryRecyclerAdapter adapter=new GalleryRecyclerAdapter(this);
              //綁定適配器
              gallery_recycler.setAdapter(adapter);
          }
          class CustomOnClickListener implements View.OnClickListener{
              @Override
              public void onClick(View v) {
                 RecyclerGalleryActivity.this.finish();
              }
          }
      }

       

      5.在看運行效果之前,我們先來看下上面的代碼,上面的代碼基本注釋已經全部加了,相應大家可以看的懂,不過我們需要來講一下上面的LayoutManager(布局管理器)。

      在上一講中我們也講到了,LayoutManger(布局管理器)該類負責將每一個Item視圖在RecyclerView中的布局。目前RecyclerView已經給我們提供三個內置管理器:LinearLayoutManger,GridLayoutManger以及StaggeredGridLayoutManager。這邊的例子中我們是采用LinearLayoutManger而且設置了橫向水平布局了。當然LinearLayoutManger還給我們提供了以下幾個方法來讓開發者方便的獲取到屏幕上面的頂部item和頂部item相關的信息:

      • findFirstVisibleItemPosition()
      • findFirstCompletlyVisibleItemPosition()
      • findLastVisibleItemPosition()
      • findLastCompletlyVisibleItemPosition()

        這邊的具體設置代碼如下:

         

                //創建布局管理器
                LinearLayoutManagerlinearLayoutManager=new LinearLayoutManager(this);
                //設置橫向
               linearLayoutManager.setOrientation(OrientationHelper.HORIZONTAL);
                //設置布局管理器
               gallery_recycler.setLayoutManager(linearLayoutManager);

         

        6.初步運行效果如下:

        /

        (三).升級加入點擊事件

        通過上面的方式我們顯示了一個類似於Gallery的效果,但是還遠遠不如實際Gallery的效果,現在只是可以有多項Item以及可以左右滑動,但是沒有點擊事件,下面我們來加入點擊事件操作。

        對於ListView來講,我們可以為ListView加入setOnItemClickListener監聽事件,但是對於RecyclerView控件來講,RecyclerView已經不再負載Item視圖的布局和顯示,這些工作已經交給了LayoutManger來做了。所以RecyclerView也沒有給我們提供類似onItemClick事件,這樣如果非得要實現類似的功能,我們開發者也可以自定義模擬實現。來,我們繼續往下看….

        1.我們最終要實現點擊列表上面每一項Item來回調點擊方法,那麼我們可以在Adapter中的每一項View上面做文章,首先我們來看一下Adapter中的onCreateViewHolder()方法:

         

         public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                Viewview=mInflater.inflate(R.layout.item_gallery_recycler,parent,false);
                ViewHolder viewHolder=new ViewHolder(view);
                return viewHolder;
            }
        2.該方法創建出了Item 視圖,然後通過ViewHolder來進行承載了,既然這樣那我們可以在View加載出來之後給它設置一些屬性例如:顏色,大小,當然也可以是點擊事件等等。那這邊我們給View添加onClick事件,然後在onClick方法把View點擊觸發的事件回調出去,同時可以回調一些參數內容出去。OK,那麼我們這邊就需要一個自定義的接口了,我們創建一個GallerRecyclerAdapter的內部類接口:

         

         

        /**
             * 類似ListView的 onItemClickListener接口
             */
            public interface OnRecyclerViewItemClickListener{
                /**
                 * Item View發生點擊回調的方法
                 * @param view   點擊的View
                 * @paramposition  具體Item View的索引
                 */
                void onItemClick(View view,intposition);
            }

         

        3.然後定義接口,同時提供set和get方法,來讓外部傳入該接口,初始化:

         

        private OnRecyclerViewItemClickListener onRecyclerViewItemClickListener;
         
            public OnRecyclerViewItemClickListener getOnRecyclerViewItemClickListener() {
                return onRecyclerViewItemClickListener;
            }
            public void setOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener onRecyclerViewItemClickListener) {
                this.onRecyclerViewItemClickListener =onRecyclerViewItemClickListener;
            }

         

        4.現在開始在onCreateViewHolder()方法中給View添加一個onClick事件,然後相應處理,判斷onRecyclerViewItemClickListener是否存在,把事件回調出去:

         

         view.setOnClickListener(newView.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                       if(onRecyclerViewItemClickListener!=null){
                           onRecyclerViewItemClickListener.onItemClick(view,(int)view.getTag());
                        }
                    }
                });

         

        5.上面的代碼中大家可能注意到onItemClick()方法中的第二個參數,獲取了tag,因為這邊的position索引值是在onBindViewHolder()方法中設置的:

         

        public voidonBindViewHolder(ViewHolder holder, int position) {
               holder.item_img.setImageResource(models.get(position).getImgurl());
               holder.item_tv.setText(models.get(position).getTitle());
                holder.itemView.setTag(position);
            }

         

        6.OK這邊我們搞定了一個Item點擊監聽方法,接下去就是使用了,

         

        adapter.setOnRecyclerViewItemClickListener(new GalleryRecyclerAdapter.OnRecyclerViewItemClickListener() {
                    @Override
                    public void onItemClick(View view,int position) {
                       Toast.makeText(RecyclerGalleryActivity.this,您點擊的Item的索引為:+position,Toast.LENGTH_SHORT).show();
                    }
                });

         

        7.現在該功能代碼整完了,運行效果如下:

        /

        (四).升級之加入分割線

        上面我們已經給每一項Item加入了點擊回調事件,但是總感覺還缺少點什麼東西,例如分隔線。很遺憾的是,RecyclerView沒有提供ListView控件這樣設置分割線的方法,不過它給我們提供了ItemDecoration類。這個ItemDecoration可以使得每一個Item在視覺上面進行分隔開來。RecyclerView沒有要求ItemDecoration必須要設置,同樣作為開發者可以選擇不設置或者設置多個Decoration。然後RecyclerView會進行相應的繪制。

        我們這邊定義了一個TestDecoration類,該類繼承自RecyclerView.Decoration。只需要實現一下的兩個方法即可:

        • onDraw(Canvas c,RecyclerView parent,RecyclerView.State state)
        • getItemOffset(Rect outRect,int itemPosition,RecyclerView parent)

          具體實現代碼如下:

           

          public class TestDecoration extends RecyclerView.ItemDecoration {
              //采用系統內置的風格的分割線
              private static final int[] attrs=newint[]{android.R.attr.listDivider};
              private Drawable mDivider;
           
              public TestDecoration(Context context) {
                  TypedArray typedArray=context.obtainStyledAttributes(attrs);
                  mDivider=typedArray.getDrawable(0);
                  typedArray.recycle();
              }
           
              /**
               * 進行自定義繪制
               * @param c
               * @param parent
               * @param state
               */
              @Override
              public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
                  int top=parent.getPaddingTop();
                  intbottom=parent.getHeight()-parent.getPaddingBottom();
                  int childCount=parent.getChildCount();
                  for(int i=0;i

           

          最後給RecyclerView添加該分隔線即可:

           

          //設置分割線
          gallery_recycler.addItemDecoration(new TestDecoration(this));

           

          運行效果如下:

          /

          (五).升級之分割線改造

          仔細看上面的運行效果,我們會發現一個問題,那就是分割線垂直分布,但是沒有自適應控件的高度,直接延伸到界面的底部了。重新檢查了有關的所有布局文件發現,高度都設置成了warp_content,但是實際的效果還是沒有自適應。原來在哪裡呢?

          真正的原因是因為RecyclerView控件已經不負責每一項VIew的顯示了,那我們來看LayoutManger(布局管理器)該進行負責Item的布局顯示了,所以我們需要進行實現一個LayoutManger,然後重寫裡邊的onMeasure()方法。計算高度即可,具體代碼如下:

           

          public class CustomLinearLayoutManager extends LinearLayoutManager {
              public CustomLinearLayoutManager(Contextcontext) {
                  super(context);
              }
           
              @Override
              public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
                  Viewview=recycler.getViewForPosition(0);
                  if(view!=null){
                     measureChild(view,widthSpec,heightSpec);
                      int mWidth=View.MeasureSpec.getSize(widthSpec);
                      intmHeight=view.getMeasuredHeight();
                     setMeasuredDimension(mWidth,mHeight);
                  }
              }
          }

           

          然後RecyclerView使用CustomLinearLayoutManger即可,運行效果如下:

          /

          (六).升級之添加刪除Item動畫

          RecyclerView控件的一個優美之處就是當裡邊Item發生變化的時候可以加入相應的動畫效果,涉及的類為RecyclerView.ItemAnimatior。一般當存在以下三種操作的時候可以加入動畫效果:

          • Item刪除
          • Item添加
          • Item移動

            當我們的數據,或者移動的時候,去掉用Adapter給我們提供的以下兩個方法即可:

            • notifyItemInserted(int position)
            • notifyItemRemoved(int position)

              那我們可以在Adapter中加入兩個方法,分別為添加Item和刪除Item的方法:

               

                //添加數據
                  public void addItem(GalleryModel model, intposition) {
                      models.add(position, model);
                      notifyItemInserted(position);
                  }
                  //刪除數據
                  public void removeItem(int position) {
                      models.remove(position);
                      notifyItemRemoved(position);
                  }

               

              然後在外部進行調用這兩個方法:

               

                  adapter.addItem(newGalleryModel(R.drawable.ic_item_gallery,Item Add),3);
                 adapter.removeItem(2);

               

              最後千萬不要忘記給RecyclerView設置動畫效果,我這邊就直接采用默認動畫了。

               

               //設置動畫
               gallery_recycler.setItemAnimator(newDefaultItemAnimator());

               

              最終運行效果如下:

              /

              (七).最後總結

              今天通過實例帶大家又重新把RecyclerView的相關使用講解了一遍,實現類似Gallery效果,當然實例中還有很多缺點,需要進一步優化,後面的文章中也會繼續更新的~

               

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved