第一次接觸RecyclerView你一定被它強大而神奇的功能所吸引,它可以實現ListView、GridView、瀑布流方式和水平列表方式,其自帶刪除和新增item的動畫,甚至簡簡單單就可以實現item拖拽和滑動刪除,其強大的功能往往讓我們歎為觀止。 今天我們一起玩RecyclerView。 本來錄製好視訊了,由於我用了Markdown版本來編寫,Markdown不能插入視訊,所以只能給大家看一張效果圖了
新建一個名為RecyclerActivity的Activity 主頁面佈局(activity_recycler.xml)很簡單<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="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"
tools:context="com.lwj.uiproject.RecyclerActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:orientation="horizontal">
<Button
android:id="@+id/layout_vertical"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="vertical"
android:layout_height="wrap_content" />
<Button
android:id="@+id/layout_horizontal"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="horizontal"
android:layout_height="wrap_content" />
<Button
android:id="@+id/layout_grid"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="grid"
android:layout_height="wrap_content" />
<Button
android:id="@+id/layout_Staggered"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="Staggered"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:orientation="horizontal">
<Button
android:id="@+id/layout_add"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="add"
android:layout_height="wrap_content" />
<Button
android:id="@+id/layout_remove"
android:layout_width="wrap_content"
android:layout_weight="1"
android:text="remove"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="#ffededed"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview_for2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
複製程式碼
接下來看主頁面檔案內容,即RecyclerActivity
public class RecyclerActivity extends BaseActivity {
private RecyclerView mRecyclerview;
private RecyclerView2Aadapter mAdapter;
private List<String> mDatas = new ArrayList<>();
private Button vertical,horizontal,grid,staggered,add,remove;
private ItemTouchHelper mItemTouchHelper;//實現item滑動
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
getDatas();
initView();
initListener();
}
private void initView() {
grid = (Button)this.findViewById(R.id.layout_grid);
horizontal = (Button)this.findViewById(R.id.layout_horizontal);
vertical = (Button)this.findViewById(R.id.layout_vertical);
staggered = (Button)this.findViewById(R.id.layout_Staggered);
add = (Button)this.findViewById(R.id.layout_add);
remove = (Button)this.findViewById(R.id.layout_remove);
mRecyclerview = (RecyclerView)this.findViewById(R.id.recyclerview_for2);
//設定點選事件
grid.setOnClickListener(mOnclickLitener);
horizontal.setOnClickListener(mOnclickLitener);
vertical.setOnClickListener(mOnclickLitener);
staggered.setOnClickListener(mOnclickLitener);
add.setOnClickListener(mOnclickLitener);
remove.setOnClickListener(mOnclickLitener);
//設定layout顯示樣式
mRecyclerview.setLayoutManager(new GridLayoutManager(this,3));
mAdapter = new RecyclerView2Aadapter(RecyclerActivity.this,mDatas);
mRecyclerview.setAdapter(mAdapter);
ItemTouchHelperCallBack back = new ItemTouchHelperCallBack(mAdapter);
mItemTouchHelper = new ItemTouchHelper(back);
mItemTouchHelper.attachToRecyclerView(mRecyclerview);//關聯Recyclerview
}
/**
* 點選事件監聽器
*/
private View.OnClickListener mOnclickLitener = new View.OnClickListener() {
@Override
public void onClick(View view) {
mAdapter.setStagger(false);
switch (view.getId()){
case R.id.layout_grid:
mRecyclerview.setLayoutManager(new GridLayoutManager(RecyclerActivity.this,3));
break;
case R.id.layout_horizontal:
mRecyclerview.setLayoutManager(new LinearLayoutManager(RecyclerActivity.this,LinearLayoutManager.HORIZONTAL,true));
break;
case R.id.layout_Staggered:
mAdapter.setStagger(true);
mRecyclerview.setLayoutManager(new StaggeredGridLayoutManager(4,LinearLayoutManager.VERTICAL));
break;
case R.id.layout_vertical:
mRecyclerview.setLayoutManager(new LinearLayoutManager(RecyclerActivity.this,LinearLayoutManager.VERTICAL,true));
break;
case R.id.layout_add:
mAdapter.addData(20);
break;
case R.id.layout_remove:
mAdapter.removeData(21);
break;
default:
break;
}
}
};
//獲取資料
public void getDatas() {
for (int i = 0; i < 100; i++) {
String data = "Itme "+i;
mDatas.add(data);
}
}
private void initListener() {
//通過回撥來設定item的點選事件
mAdapter.setOnItemOnclickListener(new RecyclerView2Aadapter.OnItemOnclickListener() {
@Override
public void onclick(String str) {
Toast.makeText(RecyclerActivity.this,str,Toast.LENGTH_SHORT).show();
}
});
//設定拖拽或者滑動的開始
mAdapter.setOnStartDragListener(new ItemTouchHelperCallBack.OnStartDragListener() {
@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
mItemTouchHelper.startDrag(viewHolder);
}
});
}
}
複製程式碼
由於RecyclerView列表的item不會像ListView一樣具有item點選事件監聽器,所以我們需要自己設定一個點選事件的監聽器回撥,這樣子就可以在activity中處理item的點選事件了。這裡還通過button的點選給使用者展示不一樣的列表,包括像ListView、GridView、水平列表和瀑布流。RecyclerView自帶拖拽和滑動刪除的功能,這裡會通過ItemTouchHelper設定它的CallBack,然後關聯上RecyclerView即可實現這功能。
下面我們看adapter檔案RecyclerView2Aadapter.java的內容
public class RecyclerView2Aadapter extends RecyclerView.Adapter implements ItemTouchHelperCallBack.ItemTouchHelperAdapterListener {
private List<String> mDatas;
private Context mContext;
private OnItemOnclickListener mOnItemOnclickListener;
private List<Integer> heights;
private boolean isStagger = false;
private ItemTouchHelperCallBack.OnStartDragListener mDragStartListener;
public RecyclerView2Aadapter(Context mContext, List<String> mDatas) {
this.mDatas = mDatas;
this.mContext = mContext;
heights = new ArrayList<Integer>();
if (mDatas != null && mDatas.size() > 0) {
for (int i = 0; i < mDatas.size(); i++) {
heights.add((int) Math.max(200, Math.random() * 550));
}
}
}
public void setOnStartDragListener(ItemTouchHelperCallBack.OnStartDragListener l){
this.mDragStartListener = l;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LinearLayout view = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.recycler_view_item, parent, false);
return new RecyclerViewItemLayout(view);
}
//繫結資料
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
RecyclerViewItemLayout item = (RecyclerViewItemLayout) holder;
int height = heights.get(position);
String str = mDatas.get(position);
setData(item, str, height);
// item.mBtn.setOnTouchListener(new OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// if (event.getAction() == MotionEvent.ACTION_DOWN) {
// mDragStartListener.onStartDrag(holder);
// }
// return false;
// }
// });
}
@Override
public int getItemCount() {
if (mDatas != null && mDatas.size() > 0) {
return mDatas.size();
}
return 0;
}
/**
* 設定資料
*
* @param item
* @param str
* @param height
*/
public void setData(RecyclerViewItemLayout item, String str, int height) {
if (TextUtils.isEmpty(str) || str == item.mTagStr) {
return;
} else {
item.mTagStr = str;
item.mBtn.setText(item.mTagStr);
if (isStagger) {
LinearLayout.LayoutParams p = (LinearLayout.LayoutParams) item.mBtn.getLayoutParams();
p.height = height;
item.mBtn.setLayoutParams(p);
} else {
LinearLayout.LayoutParams p = (LinearLayout.LayoutParams) item.mBtn.getLayoutParams();
p.height = LinearLayout.LayoutParams.WRAP_CONTENT;
item.mBtn.setLayoutParams(p);
}
}
}
private class RecyclerViewItemLayout extends RecyclerView.ViewHolder implements ItemTouchHelperCallBack.ItemTouchHelperViewHolder{
private String mTagStr;
private Button mBtn;
public RecyclerViewItemLayout(LinearLayout view) {
super(view);
mBtn = (Button) view.findViewById(R.id.item_btn);
mBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (mOnItemOnclickListener != null) {
mOnItemOnclickListener.onclick(mTagStr);
}
}
});
}
@Override
public void onItemSelected() {
itemView.setBackgroundColor(0xffadadad);
Animation animation=new ScaleAnimation(0,1.05f,0,1.05f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);//放大5%,即1.05倍,中點為縮放中心
animation.setFillAfter(true);
itemView.startAnimation(animation);
itemView.bringToFront();
itemView.setAlpha(1);//不透明
}
@Override
public void onItemClear() {
itemView.setBackgroundColor(0xffededed);
itemView.clearAnimation();//清除動畫
}
}
/**
* 拖拽實現
* @param fromPosition
* @param toPosition
* @return
*/
@Override
public boolean onItemMove(int fromPosition, int toPosition) {
Collections.swap(mDatas, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
return true;
}
/**
* 滑動刪除
* @param position
*/
@Override
public void onItemDismiss(int position) {
mDatas.remove(position);
notifyItemRemoved(position);
}
public interface OnItemOnclickListener {
void onclick(String str);
}
/**
* 設定item點選事件的回撥
* @param listener
*/
public void setOnItemOnclickListener(OnItemOnclickListener listener) {
this.mOnItemOnclickListener = listener;
}
public void setStagger(boolean stagger) {
isStagger = stagger;
}
/**
* 往列表新增一個item
* @param position
*/
public void addData(int position) {
mDatas.add(position, "additem" + position);
notifyItemInserted(position);
}
/**
* 刪除列表的一個item
* @param position
*/
public void removeData(int position) {
mDatas.remove(position);
notifyItemRemoved(position);
}
}
複製程式碼
<?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="vertical">
<Button
android:id="@+id/item_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:text="hello" />
</LinearLayout>
複製程式碼
RecyclerView的adapter需要實現RecyclerView.Adapter,預設需要重寫裡面的getItemCount、onBindViewHolder、onCreateViewHolder這三個方法,這裡需要ItemTouchHelperAdapterListener介面,實現item拖拽和滑動的回撥。RecyclerView具有的adapter好處就是具有解綁特性,為我們區分了item介面建立和資料繫結的方法,而不像ListView一樣都集中在getView方法中處理。RecyclerView.ViewHolder本身已經具有holder的快取。所以我們不用做特殊處理,大大提高了開發效率。 這裡建立的holder(RecyclerViewItemLayout)除了要繼承ViewHolder之外還要實現ItemTouchHelperViewHolder這個介面,這裡介面主要通過回撥來實現item拖拽和滑動,當使用者按住(選擇)item時和完成操作時item所做的一些效果處理。
接下來我們看看實現拖拽和滑動的ItemTouchHelper.Callback
public class ItemTouchHelperCallBack extends ItemTouchHelper.Callback{
private static final float ALPHA = 1.0f;
private ItemTouchHelperAdapterListener mItemTouchHelperAdapterListener;
public ItemTouchHelperCallBack(ItemTouchHelperAdapterListener l){
this.mItemTouchHelperAdapterListener = l;
}
/**
* 是否支援長按
* @return
*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}
/**
* 是否支援滑動
* @return
*/
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
/**
* 滑動方向
* @param recyclerView
* @param viewHolder
* @return
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if(recyclerView.getLayoutManager() instanceof GridLayoutManager || recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager)
{
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
final int swipeFlags = 0;
return makeMovementFlags(dragFlags, swipeFlags);
}
else
{
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
}
}
/**
* 拖拽完成
* @param recyclerView
* @param viewHolder
* @param target
* @return
* Called when ItemTouchHelper wants to move the dragged item from its old position to the new position.
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
if(viewHolder.getItemViewType() != target.getItemViewType())
{
return false;
}
if (mItemTouchHelperAdapterListener != null){
mItemTouchHelperAdapterListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
}
return true;
}
/**
* 左右滑動刪除
* Called when a ViewHolder is swiped by the user.
* @param viewHolder
* @param direction
*/
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
if (mItemTouchHelperAdapterListener != null){
mItemTouchHelperAdapterListener.onItemDismiss(viewHolder.getAdapterPosition());
}
}
/**
* 拖拽的時候給item新增一個背景色
*
* @param viewHolder
* @param actionState
* Called when the ViewHolder swiped or dragged by the ItemTouchHelper is changed.
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if(actionState != ItemTouchHelper.ACTION_STATE_IDLE)
{
if(viewHolder instanceof ItemTouchHelperViewHolder)
{
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder)viewHolder;
itemViewHolder.onItemSelected();
}
}
super.onSelectedChanged(viewHolder, actionState);
}
/**
* 在這個方法實現互動規則
* @param c
* @param recyclerView
* @param viewHolder
* @param dX
* @param dY
* @param actionState
* @param isCurrentlyActive
*/
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE)
{
final float alpha = ALPHA - Math.abs(dX) / (float)viewHolder.itemView.getWidth();
viewHolder.itemView.setAlpha(alpha);
viewHolder.itemView.setTranslationX(dX);
}
else
{
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
/**
* Called by the ItemTouchHelper
* when the user interaction with an element is over
* 操作完成並且其動畫也結束後會呼叫該方法
* 一般在該方法內恢復ItemView的初始狀態
* and it also completed its animation.
* @param recyclerView
* @param viewHolder
*
*/
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
viewHolder.itemView.setAlpha(ALPHA);
if(viewHolder instanceof ItemTouchHelperViewHolder)
{
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder)viewHolder;
itemViewHolder.onItemClear();
}
}
public interface ItemTouchHelperViewHolder
{
void onItemSelected();
void onItemClear();
}
public interface ItemTouchHelperAdapterListener
{
boolean onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}
//當檢視請求開始挪動是呼叫
public interface OnStartDragListener
{
void onStartDrag(RecyclerView.ViewHolder viewHolder);
}
}
複製程式碼
這裡主要是實現item拖拽和滑動的功能,以及一些設定。使用者需要實現列表的item的滑動和拖拽功能就必須要重寫Callback的抽象方法才能完成。
參考文章: 吳小龍同學.《Android ItemTouchHelper 實踐》
有發現問題的可以留言,喜歡的點個贊。你的喜歡就是我分享的動力!!!