一、簡介:
RecyclerView 是 Android5.0 之后新出的控件。
RecyclerView 是 ListView 的增強(qiáng)版,不僅能實現(xiàn) ListView 的效果,還優(yōu)化了 ListView 的很多不足之處。
想對于 ListView 來說,官方更推薦使用 RecyclerView
二、使用 RecyclerView
- 演示思路:布局 RecyclerView ,CardView 充當(dāng)其 Item !
2.1 app 的 build.gradle 中添加依賴
// cardview 是因為這個 Demo 也要用到 cardview
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
2.2 主頁面布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--標(biāo)題欄-->
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
android:fitsSystemWindows="true"
android:minHeight="?attr/actionBarSize"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<!--自定義控件-->
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:gravity="center"
android:text="FloatingActionButton"
android:textSize="20dp"
android:textStyle="bold" />
</android.support.v7.widget.Toolbar>
<!--RecyclerView-->
<android.support.v7.widget.RecyclerView
android:layout_below="@id/toolbar"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
<!--FloatingActionButton-->
<android.support.design.widget.CoordinatorLayout
android:layout_alignBottom="@id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.FloatingActionButton
android:id="@+id/floating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/floating_icon"
app:fabSize="normal"
app:pressedTranslationZ="10dp"
app:rippleColor="@color/colorAccent"
/>
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
2.3 Actiity 和 Adapter 的代碼
public class MyRecyclerViewActivity extends AppCompatActivity {
@BindView(R.id.floating)
FloatingActionButton floating;
@BindView(R.id.toolbar_title)
TextView toolbarTitle;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
private Snackbar snackbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycleview);
ButterKnife.bind(this);
//設(shè)置透明狀態(tài)欄
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
localLayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
}
toolbar.setTitle("");
setSupportActionBar(toolbar);
toolbar.setNavigationIcon(R.drawable.setting);
initRecyclerViewData();
initRcyclerView();
}
private void initRcyclerView() {
LinearLayoutManager manager = new LinearLayoutManager(this);
// GridLayoutManager manager = new GridLayoutManager(getApplicationContext(),2);
// StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2, OrientationHelper.HORIZONTAL);
recyclerView.setLayoutManager(manager);
myRecyclerAdapter = new MyRecyclerAdapter();
recyclerView.setAdapter(myRecyclerAdapter);
}
private List<String> listData;
/**
* 初始化 RecyclerView 的數(shù)據(jù)
*/
private void initRecyclerViewData() {
listData = new ArrayList<>();
int m = 0;
for (int i = 0; i < 20; i++) {
listData.add("珞璃之神" + m);
m++;
}
}
private MyRecyclerAdapter myRecyclerAdapter;
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_card_view, parent, false);
// View view = View.inflate(getApplicationContext(), R.layout.activity_card_view, parent);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.cardText.setText(listData.get(position));
}
@Override
public int getItemCount() {
return listData.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.card_text)
TextView cardText;
@BindView(R.id.card_image)
ImageView cardImage;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
}
注意: RecyclerView 的三種 manager ,分別為 線性、宮格、瀑布流樣式。
2.4 RecyclerView 的 item 的樣式為:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView 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"
android:layout_marginBottom="@dimen/cardview_margin"
android:layout_marginTop="@dimen/cardview_margin"
android:layout_marginLeft="@dimen/cardview_margin_left_right"
android:layout_marginRight="@dimen/cardview_margin_left_right"
app:cardCornerRadius="5dp"
android:foreground="?android:attr/selectableItemBackground"
app:cardElevation="10dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_weight="5"
android:id="@+id/card_image"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:scaleType="centerCrop"
android:src="@drawable/cardview_icon" />
<TextView
android:layout_weight="1"
android:id="@+id/card_text"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:layout_below="@id/card_image"
android:text="珞神"
android:textColor="#ba2f2f"
android:textSize="30dp" />
</LinearLayout>
</android.support.v7.widget.CardView>
2.5 運行結(jié)果如下:
-
LinearLayoutManager manager = new LinearLayoutManager(this); 結(jié)果:
image -
GridLayoutManager manager = new GridLayoutManager(getApplicationContext(),2);結(jié)果如下:
image -
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2, OrientationHelper.HORIZONTAL);結(jié)果如下:
image
三、RecyclerView 添加條目點擊事件
3.1 RecyclerView 并沒有對外暴露的具體的單擊或長按監(jiān)聽事件,需要我們自己來處理單擊或長按事件,如下所示:
recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener(){
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
這種需要自己增加單擊或長按事件的邏輯,然后利用接口回調(diào)出去。
Android 給我們提供了一個手勢監(jiān)測幫助類 GestureDetector ,我們可以借助這個類來處理不同的手勢,我們重新建個類實現(xiàn) RecyclerView.OnItemTouchListener 接口。代碼如下:
/**
* 自定義手勢監(jiān)聽
*/
public class RecyclerViewClickListener implements RecyclerView.OnItemTouchListener {
// GestureDetectorCompat 是為了版本兼容
private GestureDetectorCompat mGestureDetector;
private OnItem2ClickListener mListener;
//自定義內(nèi)部監(jiān)聽
public interface OnItem2ClickListener {
//單擊
void onItemClick(View view, int position);
//長按
void onItemLongClick(View view, int position);
}
public RecyclerViewClickListener(Context context, final RecyclerView mRecyclerView,
OnItem2ClickListener listener) {
this.mListener = listener;
// SimpleOnGestureListener 是為了選擇重寫需要的方法
mGestureDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
//單擊事件
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.i("mGestureDetector","onSingleTapUp");
View childViewUnder = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
if (childViewUnder != null && mListener != null) {
mListener.onItemClick(childViewUnder, mRecyclerView.getChildLayoutPosition(childViewUnder));
return true;
}
return false;
}
//長按事件
@Override
public void onLongPress(MotionEvent e) {
Log.i("mGestureDetector","onLongPress");
View childView = mRecyclerView.findChildViewUnder(e.getX(),e.getY());
if(childView != null && mListener != null){
mListener.onItemLongClick(childView,mRecyclerView.getChildLayoutPosition(childView));
}
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
//是否攔截事件交給 mGestureDetector 處理
if(mGestureDetector.onTouchEvent(e)){
return true;
}else
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
- 代碼中只實現(xiàn)了,單擊和長按事件的回調(diào),更多的事件操作方法可以參考 GestureDetector 類。
3.2 另一種方式是在 Adapter 的 onBindViewHolder 方法中,利用 View 本身的監(jiān)聽事件,來設(shè)置回調(diào)監(jiān)聽,代碼如下:
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {
private List<String> listData;
public MyRecyclerAdapter(List<String> listData){
this.listData = listData;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_card_view, parent, false);
// View view = View.inflate(getApplicationContext(), R.layout.activity_card_view, parent);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
/**
* 在 onBindViewHolder 中,設(shè)置單擊和長按的監(jiān)聽回調(diào)
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.cardText.setText(listData.get(position));
//單擊
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//觸發(fā)自定義監(jiān)聽的單擊事件
onItemClickListener.onItemClick(holder.itemView,position);
}
});
//長按
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//觸發(fā)自定義監(jiān)聽的長按事件
onItemClickListener.onItemLongClick(holder.itemView,position);
return true;//表示此事件已經(jīng)消費,不會觸發(fā)單擊事件
}
});
}
@Override
public int getItemCount() {
return listData.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.card_text)
TextView cardText;
@BindView(R.id.card_image)
ImageView cardImage;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public void setOnItemClickListener(MyRecyclerAdapter.OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
private OnItemClickListener onItemClickListener;
/**
* 自定義監(jiān)聽回調(diào),RecyclerView 的 單擊和長按事件
*/
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
}
3.3 兩種添加點擊事件比較
第一種方式更加靈活,解耦性更高,第二種因為設(shè)置在 Adapter 內(nèi),只能用作特定的 RecyclerView
第二種相對第一種來說,更加簡便,實現(xiàn)起來也方便,也比較好理解。
第一種還能用于更加復(fù)雜的手勢監(jiān)聽,我們可以利用 GestureDetector 類來實現(xiàn)更加復(fù)雜的事件監(jiān)聽回調(diào),而第二種監(jiān)聽的事件比較有限。


