2016年2月28日 星期日

RecyclerView

RecyclerView
can do

horizontal list
grid list
staggered frid layout

morever,we can customed the animation

let’s see how a list view use:
recycle view use in this way:
the view holder in list view is optional,but in recycle is must!!!

we can set a view holder onclick listener,not se the onclick listener for the Recycle,the view holder can access the adapter position that has beenclicked.

how to patice it?

Exercise:
start from

replace list view by recycle view
step:


step2:add the library
compile 'com.android.support:recyclerview-v7:23.0.+'

how to use recycle to replace the list view?
  1. use android.support.v7.widget.RecyclerView to replace listview in the layout xml
  2. in the program,change the ListView to android.support.v7.widget.RecyclerView
  3. than you will fins that some method can not use,like setOnItemClickListener or setEmptyView
  4. create a linear layout manager for the recycle view
LinearLayoutManager mLayoutManager mLayoutManager = new LinearLayoutManager(getContext());
5.create a Forecast Adapter
how?????
create a class that extends RecyclerView.Adapter<MyAdapter.ViewHolder>

craet a VieHolder in the Adapter calss
example:
public class ViewHolder extends RecyclerView.ViewHolder {
       public final ImageView mIconView;
       public final TextView mDateView;
       public final TextView mDescriptionView;
       public final TextView mHighTempView;
       public final TextView mLowTempView;

       public ViewHolder(View view) {
           super(view);
           mIconView = (ImageView) view.findViewById(R.id.list_item_icon);
           mDateView = (TextView) view.findViewById(R.id.list_item_date_textview);
           mDescriptionView = (TextView) view.findViewById(R.id.list_item_forecast_textview);
           mHighTempView = (TextView) view.findViewById(R.id.list_item_high_textview);
           mLowTempView = (TextView) view.findViewById(R.id.list_item_low_textview);

       }
   }
it should hold all the view that in the listview iteam view.
the super(view)  is must

overidemethod:
1.onCreateViewHolder
use to crate the view that will show in a list iteam,and return a view holder that hold the view
example:

public ForecastAdapterforRecycelview.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
       int layoutId = -1;
       switch (viewType) {
           case VIEW_TYPE_TODAY: {
               layoutId = R.layout.list_item_forecast_today;
               break;
           }
           case VIEW_TYPE_FUTURE_DAY: {
               layoutId = R.layout.list_item_forecast;
               break;
           }
       }
       View view = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
       ViewHolder vh = new ViewHolder(view);
       return vh;
   }

2.getItemViewType
OPtional,can use to show different view in a same recycle view,accroading the position ,return different int

public int getItemViewType(int position) {
       return (position == 0) ? VIEW_TYPE_TODAY : VIEW_TYPE_FUTURE_DAY;
   }


3.onBindViewHolder

bind the data to the view

public void onBindViewHolder(ForecastAdapterforRecycelview.ViewHolder holder, int position) {

      mCursor.moveToPosition(position);
       int weatherId = mCursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID);
       int defaultImage;

       switch (getItemViewType(mCursor.getPosition())) {
           case VIEW_TYPE_TODAY:
               defaultImage = Utility.getArtResourceForWeatherCondition(weatherId);
               break;
           default:
               defaultImage = Utility.getIconResourceForWeatherCondition(weatherId);
       }

       if (Utility.usingLocalGraphics(mContext)) {
           holder.mIconView.
                   setImageResource(defaultImage);
       } else {
           Glide.with(mContext)
                   .load(Utility.getArtUrlForWeatherCondition(mContext, weatherId))
                   .error(defaultImage)
                   .crossFade()
                   .into(holder.mIconView);
       }

       // Read date from cursor
       long dateInMillis = mCursor.getLong(ForecastFragment.COL_WEATHER_DATE);
       // Find TextView and set formatted date on it
       holder.mDateView.setText(Utility.getFriendlyDayString(mContext, dateInMillis));

       // Read weather forecast from cursor
       String description = Utility.getStringForWeatherCondition(mContext, weatherId);
       // Find TextView and set weather forecast on it
       holder.mDescriptionView.setText(description);
       holder.mDescriptionView.setContentDescription(mContext.getString(R.string.a11y_forecast, description));

       // For accessibility, we don't want a content description for the icon field
       // because the information is repeated in the description view and the icon
       // is not individually selectable

       // Read high temperature from cursor
       double high = mCursor.getDouble(ForecastFragment.COL_WEATHER_MAX_TEMP);
       String highString = Utility.formatTemperature(mContext, high);
       holder.mHighTempView.setText(highString);
       holder.mHighTempView.setContentDescription(mContext.getString(R.string.a11y_high_temp, highString));

       // Read low temperature from cursor
       double low = mCursor.getDouble(ForecastFragment.COL_WEATHER_MIN_TEMP);
       String lowString = Utility.formatTemperature(mContext, low);
       holder.mLowTempView.setText(lowString);
       holder.mLowTempView.setContentDescription(mContext.getString(R.string.a11y_low_temp, lowString));

   }


4.getItemCount
return how many data in a cursor or array,depend what you input to be the source or the array adapter

now, we can use the recycle view

mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

       // use this setting to improve performance if you know that changes
       // in content do not change the layout size of the RecyclerView
       mRecyclerView.setHasFixedSize(true);

       // use a linear layout manager
       mLayoutManager = new LinearLayoutManager(this);
       mRecyclerView.setLayoutManager(mLayoutManager);

       // specify an adapter (see also next example)
       mAdapter = new MyAdapter(myDataset);
       mRecyclerView.setAdapter(mAdapter);
important *****
the setLayoutManager is must,if not set,the recycle view will not show anything.


next we will talk about the handle click of the Recycle view

Add back the onClickListerner
package pom2.poly.com.userecyclerviewnotlistview;

/**
* Created by User on 26/1/2016.
*/


import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.DataObjectHolder> {
   private static String LOG_TAG = "MyRecyclerViewAdapter";
   private static MyClickListener myClickListener;
   private ArrayList<DataObject> mDataset;

   //create a constructor to receive the DataSet
   public MyRecyclerViewAdapter(ArrayList<DataObject> myDataset) {
       mDataset = myDataset;
   }

   //TODO:why have a interface MyClickListener here?
   public interface MyClickListener {
       public void onItemClick(int position, View v);
   }


   //TODO :why have  on ClickListener?
   public void setOnItemClickListener(MyClickListener myClickListener) {
       this.myClickListener = myClickListener;
   }

   //Because the View Holder is in the Asapter for Reycle view, we need
   // to to create our own ViewHolder first ,the view holder hold all the view in a
   // Iteam of the Recycle View,we define what will show in each Iteam of the Recycle view by the XML,
   // recycleriew_iteam.xml,in that,it has two TextView
   //TODO:why implement View.OnClickListener  and overview onClick.Becuase the Recycle view do't have a onClickListerner,so we need to set the onItemClicl to each view first,than use the  interface  MyClickListener to allow define the what will do after click the view.
   // TODO The setOnItemClickListener is a method to accept the myClickListener object
   public static class DataObjectHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
       TextView label;
       TextView dateTime;

       public DataObjectHolder(View itemView) {
           super(itemView);
           label = (TextView) itemView.findViewById(R.id.textView);
           dateTime = (TextView) itemView.findViewById(R.id.textView2);
           Log.i(LOG_TAG, "Adding Listener");
           itemView.setOnClickListener(this);
       }

       @Override
       public void onClick(View v) {
           myClickListener.onItemClick(getPosition(), v);
       }
   }
//here will return the ViewHolder we create,so we need to inflate the XML to view that we decide what will show in each view
   @Override
   public DataObjectHolder onCreateViewHolder(ViewGroup parent,
                                              int viewType) {
       View view = LayoutInflater.from(parent.getContext())
               .inflate(R.layout.recyclerview_item, parent, false);

       DataObjectHolder dataObjectHolder = new DataObjectHolder(view);
       return dataObjectHolder;
   }


   //bind the data to the view,view get from the view holder
   @Override
   public void onBindViewHolder(DataObjectHolder holder, int position) {
       holder.label.setText(mDataset.get(position).getmText1());
       holder.dateTime.setText(mDataset.get(position).getmText2());
   }

   //add iteam to the Dataset,and notify change to the adtapter.
   public void addItem(DataObject dataObj, int index) {
       mDataset.add(dataObj);
       notifyItemInserted(index);
   }

   public void deleteItem(int index) {
       mDataset.remove(index);
       notifyItemRemoved(index);
   }

   //how many iteam,should be the same with the nuber of the Data set size
   @Override
   public int getItemCount() {
       return mDataset.size();
   }



Add back the empty view
for a list view,the mListView.setEmptyView(emptyView) can make the list view show the speficicef view when the list view is empty.
But Recycle view don’t have tis feacture.
private View empty;

public View getEmpty() {
       return empty;
   }

   public void setEmpty(View empty) {
       this.empty = empty;
   }


public void swapCursor(Cursor mCursor) {
       this.mCursor = mCursor;
       if (mCursor.getCount() == 0) {
           empty.setVisibility(View.VISIBLE);
       } else {
           empty.setVisibility(View.GONE);
           notifyDataSetChanged();
       }


   }


the concept is when the cursor is empty,set the empty view is VISIBLE.if tge cursor is not empty,set it gone.