[Android]RecyclerView的簡單示例

去年google的IO上就展示了一個新的ListView,它就是RecyclerView。

以下是官方的說明,我英語能力有限,不過我大概這麼理解:RecyclerView會比ListView更具有拓展性,使用更有效率,而且更靈活了,具體怎麼樣,時隔一年,我們也發現了它越來越強大,所以有必要去認識一下這個小夥伴了。

The RecyclerView widget is a more advanced and flexible version of ListView. This widget is a container for displaying large data sets that can be scrolled very efficiently by maintaining a limited number of views. Use the RecyclerViewwidget when you have data collections whose elements change at runtime based on user action or network events.

The RecyclerView class simplifies the display and handling of large data sets by providing:

  • Layout managers for positioning items
  • Default animations for common item operations, such as removal or addition of items

You also have the flexibility to define custom layout managers and animations for RecyclerView widgets.


我們可以在最新版本的support-v7上找到這個玩意兒,本文在v21上找到這個jar的:sdk\extras\android\m2repository\com\android\support\recyclerview-v7\21.0.0,在目錄下將recyclerview-v7-21.0.0.aar解壓,取出classes.jar,你可以更名爲:android-support-v7-recyclerview.jar,至少我是這麼幹的微笑

好了,進入這次demo的主題

1.demo結構

                 

2.示例效果圖


3.讓我們邊看代碼邊瞭解一下,這個控件吧,首先在界面佈局文件中引入這個組件:

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

        <RadioGroup
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:checkedButton="@+id/linearlayout_rb"
            android:gravity="center_horizontal"
            android:orientation="horizontal" >

            <RadioButton
                android:id="@+id/linearlayout_rb"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/linearlayout" />

            <RadioButton
                android:id="@+id/gridlayout_rb"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/gridlayout" />
        </RadioGroup>
<span style="white-space:pre">	</span>
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:scrollbars="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</RelativeLayout>

4.下面就是怎麼使用它,這邊就是簡單的使用方法,在代碼上我已經加上了註釋,簡單理解一下吧。

MainActivity.java

package org.jan.components.demo;

import java.util.ArrayList;

import org.jan.components.demo.CustomAdapter.OnItemPressedListener;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.RecyclerListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.RadioButton;
import android.widget.Toast;
/**
 * android recyclerView的簡單實例代碼
 * @author jan
 */
public class MainActivity extends Activity {
	private static final String TAG = "MainActivity";
	private static final String KEY_LAYOUT_MANAGER = "layoutManager";
	private enum LayoutManagerType {
		GRID_LAYOUT_MANAGER, LINEAR_LAYOUT_MANAGER
	}

	private RadioButton mLinearlayoutButton;
	private RadioButton mGridLayoutButton;

	private RecyclerView mRecyclerView;
	private CustomAdapter mAdapter;
	private RecyclerView.LayoutManager mLayoutManager;
	private LayoutManagerType mCurrentLayoutManagerType;
	//建立的模擬數據
	private ArrayList<String> mDataList;
	//網格佈局中的設置列數
	private static int SpanCount=3;
	//模擬數據的個數
	private static int DataSize = 100;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initDatas();
		initViews(savedInstanceState);
	}

	private void initViews(Bundle savedInstanceState) {
		mLinearlayoutButton = (RadioButton) findViewById(R.id.linearlayout_rb);
		mLinearlayoutButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				setRecyclerViewManagerType(LayoutManagerType.LINEAR_LAYOUT_MANAGER);
			}
		});
		mGridLayoutButton = (RadioButton) findViewById(R.id.gridlayout_rb);
		mGridLayoutButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				setRecyclerViewManagerType(LayoutManagerType.GRID_LAYOUT_MANAGER);
			}
		});
		mCurrentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER;
		if(savedInstanceState!=null){
			 mCurrentLayoutManagerType = (LayoutManagerType) savedInstanceState
	                    .getSerializable(KEY_LAYOUT_MANAGER);
			 Log.i(TAG, "mCurrentLayoutManagerType="+mCurrentLayoutManagerType);
		}
		
		mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
		setRecyclerViewManagerType(mCurrentLayoutManagerType);
		mAdapter = new CustomAdapter(mDataList);
		mRecyclerView.setAdapter(mAdapter);
		//設置recycler擁有固定的大小,提高展示效率
		mRecyclerView.setHasFixedSize(true);
		//設置默認的動畫,在移除和添加的效果下展現,現在github上可以找到許多拓展,有興趣的可以找找
		mRecyclerView.setItemAnimator(new DefaultItemAnimator());
		//實現我們給Adapter監聽的方法,因爲recyclerview沒有Listview的OnClick和OnlongClick相似的方法
		mAdapter.setOnItemPressedListener(new OnItemPressedListener() {
			@Override
			public void onItemClick(int position) {
				Toast.makeText(MainActivity.this, "你點擊了 item-"+mDataList.get(position), Toast.LENGTH_SHORT).show();
			}
			
			@Override
			public boolean OnItemLongClick(int position) {
				//這裏模擬了刪除的功能
				removeItemByPosition(position);
//				insertItemByPosition(position);
				Toast.makeText(MainActivity.this, "你長按了 item-"+mDataList.get(position), Toast.LENGTH_SHORT).show();
				return true;
			}
		});
		mRecyclerView.setRecyclerListener(new RecyclerListener() {
			//資源回收後被調用
			@Override
			public void onViewRecycled(ViewHolder viewHolder) {
				CustomAdapter.ViewHolder vh = (org.jan.components.demo.CustomAdapter.ViewHolder) viewHolder;
				Log.d(TAG, "onViewRecycled->"+vh.getItemText().getText());
			}
		});
	}
	
	//創建模擬的數據
	private void initDatas() {
		mDataList = new ArrayList<String>();
		for (int i = 0; i < DataSize; i++) {
			mDataList.add(String.format(getString(R.string.iamstudent), i));
		}
	}
	/**
	 * 可以改變recycler的佈局顯示方式
	 * @param type
	 */
	protected void setRecyclerViewManagerType(LayoutManagerType type) {
		int scrollPosition = 0;
		if (mRecyclerView.getLayoutManager() != null) {
			scrollPosition = ((LinearLayoutManager) mRecyclerView
					.getLayoutManager())
					.findFirstCompletelyVisibleItemPosition();
		}
		switch (type) {
		//網狀
		case GRID_LAYOUT_MANAGER:
			mLayoutManager = new GridLayoutManager(this, SpanCount);
			mCurrentLayoutManagerType = LayoutManagerType.GRID_LAYOUT_MANAGER;
			break;
		//線性,如list
		case LINEAR_LAYOUT_MANAGER:
			mLayoutManager = new LinearLayoutManager(this);
			mLayoutManager.canScrollHorizontally();
			mCurrentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER;
			break;
		default:
			mLayoutManager = new LinearLayoutManager(this);
			mCurrentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER;
			break;
		}
		mRecyclerView.setLayoutManager(mLayoutManager);
		mRecyclerView.scrollToPosition(scrollPosition);
	}
	
	/**
	 * 通過RecyclerView的adapter來移除指定位置的數據
	 * @param position
	 */
	protected void removeItemByPosition(int position) {
		if(mAdapter!=null&&position>0){			
			mAdapter.notifyItemRemoved(position);
			mDataList.remove(position);
			mAdapter.notifyItemRangeChanged(position, mAdapter.getItemCount());
			//你如果用了這個 ,就沒有動畫效果了。
//			mAdapter.notifyDataSetChanged();
		}
	}
	//對應這是可以新增指定索引的
	protected void insertItemByPosition(int position) {
		if(mAdapter!=null&&position>0){			
			mAdapter.notifyItemInserted(position);
			mDataList.add(position, String.format(getString(R.string.iamstudent), position));
			mAdapter.notifyItemRangeChanged(position, mAdapter.getItemCount());
		}
	}
	
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		outState.putSerializable(KEY_LAYOUT_MANAGER, mCurrentLayoutManagerType);
		super.onSaveInstanceState(outState);
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);
	}

}
5.這個customAdapter是實現了RecyclerView.Adapter,其中的ViewHolder貌似是給我們自己定義的,我沒看過源碼,但我的直覺告訴我他一定是優化了ListView對viewholder的重複利用。

package org.jan.components.demo;

import java.util.List;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

public class CustomAdapter extends
		RecyclerView.Adapter<CustomAdapter.ViewHolder> {

	private List<String> dataList;
	
	private OnItemPressedListener onItemPressedListener;

	public CustomAdapter(List<String> data) {
		this.dataList = data;
	}

	@Override
	public int getItemCount() {
		return dataList.size();
	}
	//替換視圖內的內容
	@Override
	public void onBindViewHolder(ViewHolder viewHolder, int position) {
		viewHolder.getDrawableId().setBackgroundResource(R.drawable.school_student);
		viewHolder.getItemText().setText(dataList.get(position));
	}
	//由RecyclerView的Layout manager來生成一個新的ViewHolder
	@Override
	public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
		View v = LayoutInflater.from(viewGroup.getContext()).inflate(
				R.layout.layout_row_item, viewGroup, false);
		return new ViewHolder(v);
	}
	/**
	 * 繼承RecyclerView的ViewHolder來自定義一個視圖內的ViewHolder
	 */
	public class ViewHolder extends RecyclerView.ViewHolder {
		
		private ImageView drawableId;
		private TextView itemText;
		
		public ViewHolder(View itemView) {
			super(itemView);
			if(itemView!=null){
				//這裏我爲這個View添加了點擊和長按事件的監聽綁定,爲了使本demo更像一個listView
				itemView.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						if(onItemPressedListener!=null){
							onItemPressedListener.onItemClick(getPosition());
						}
					}
				});
				itemView.setOnLongClickListener(new OnLongClickListener() {
					@Override
					public boolean onLongClick(View v) {
						if(onItemPressedListener!=null){
							return onItemPressedListener.OnItemLongClick(getPosition());
						}
						return false;
					}
				});
				drawableId = (ImageView) itemView.findViewById(R.id.item_image);
				itemText = (TextView) itemView.findViewById(R.id.item_text);
			}
		}

		public ImageView getDrawableId() {
			return drawableId;
		}
		
		public TextView getItemText() {
			return itemText;
		}
	}

	public void setOnItemPressedListener(
			OnItemPressedListener onItemPressedListener) {
		this.onItemPressedListener = onItemPressedListener;
	}

	protected static interface OnItemPressedListener{
		void onItemClick(int position);
		boolean OnItemLongClick(int position);
	}
}
好,代碼都講的很清楚簡潔,主要是爲了增加對RecyclerView的認識,現在很多新的app,都已經加入了這組件,很多大牛也寫了對他的強大的拓展。

我在這裏也添加一個有進階性的博文,可供你我有時間學習

Android RecyclerView 使用完全解析 體驗藝術般的控件

[Android]使用RecyclerView替代ListView(二)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章