【RecyclerView】Android 橫豎屏切換 超便捷解決方案
相信Android 開發者大多數都遇到過橫豎屏切換的需求,往往最後選擇了鎖定豎屏,或者鎖定橫屏的體驗。或者每次切換螢幕就要切換顯示資料的控制元件。谷歌官方推出的RecyclerView控制元件讓你不再有這樣的煩惱。
最近這兩天又不是很忙了,閒下來看了些關於5.0的一些特性,比如材料設計規範、陰影、主題等等,還有RecyclerView和CardView這兩個不錯的控制元件。看到RecyclerView的時候感覺眼前一亮,毫無疑問,它能夠完全勝任ListView,GridView以及現在流行的瀑布流(交錯佈局)顯示,並且有著高度解耦,高自由度(自定義分隔線,自定義載入/刪除動畫等)等特點。
在這裡,我用它寫了一個橫豎屏切換便捷解決方案的Demo。
本demo於API 23 + eclipse環境中完成(但本demo相容低版本,如下載demo可以修改最低版本)
1.獲取RecyclerView的jar包
RecyclerView雖然是谷歌官方推出的控制元件,但是為了相容5.0以前的系統版本,它是屬於V7相容包下獨立打包的。所以如果我們要使用RecyclerView的話需要匯入這個jar包。
更新SDK Manager 中Extras的support library到21+版本後,其jar包在如下位置:
sdk\extras\android\support\v7\recyclerview\libs\android-support-v7-recyclerview.jar
如果不方便更新sdk的話,點選jar包下載地址
匯入專案並add to build path。
2.Activity中橫豎屏切換控制
OrientationChangeActivity.java
/**
* @author 塵笑ys
* RecyclerView 橫豎屏切換demo
*/
public class OrientationChangeActivity extends Activity {
private RecyclerView recyclerView;
private ArrayList<String> datas = new ArrayList<String>();
private LinearLayoutManager mLlayoutmanager;
private GridLayoutManager mGlayoutmanager;
CharAdapter charad;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
//切換螢幕時儲存資料,如有資料,則不再進行資料的初始化
if (savedInstanceState != null && savedInstanceState.getStringArrayList("data") != null) {
datas = savedInstanceState.getStringArrayList("data");
}else {
initData();
}
//豎屏線性展示
mLlayoutmanager = new LinearLayoutManager(this);
//橫屏每行顯示3個
mGlayoutmanager = new GridLayoutManager(this,3);
reviewonScreenChanged(getResources().getConfiguration());
recyclerView.setAdapter(charad = new CharAdapter(this, datas));
charad.setOnItemClickLitener(new OnItemClickLitener() {
@Override
public void onItemLongClick(View view, int position) {
//這裡要先使用這個資料再刪除,因為一旦刪除,就獲取不到這個資料了,獲取的就是下一個資料了
Toast.makeText(OrientationChangeActivity.this, datas.get(position)+'\t'+"delete...", Toast.LENGTH_SHORT).show();
charad.removeData(position);
}
@Override
public void onItemClick(View view, int position) {
Toast.makeText(OrientationChangeActivity.this, datas.get(position), Toast.LENGTH_SHORT).show();
}
});
}
private void reviewonScreenChanged(Configuration newConfig) {
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//橫屏
recyclerView.setLayoutManager(mGlayoutmanager);
}else {
//豎屏
recyclerView.setLayoutManager(mLlayoutmanager);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
reviewonScreenChanged(newConfig);
}
private void initData() {
for (int i = 'A'; i <= 'z'; i++) {
datas.add((char)i + "");
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArrayList("data", datas);
}
}
3.RecyclerView.Adapter
CharAdapter.java
/**
* @author 塵笑ys
*
*/
public class CharAdapter extends RecyclerView.Adapter<CharAdapter.MyViewHolder>{
//型別用自定義的ViewHolder
private List<String> mDatas;
private LayoutInflater mInflater;
//RecyclerView目前需要自己來定義介面
public interface OnItemClickLitener
{
//點選事件
void onItemClick(View view, int position);
//長按事件
void onItemLongClick(View view , int position);
}
private OnItemClickLitener mOnItemClickLitener;
//設定監聽的方法,注意引數是CharAdapter.OnItemClickLitener而不是View.OnItemClickLitener
public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
{
this.mOnItemClickLitener = mOnItemClickLitener;
}
//構造時傳入資料,如果考慮資料解耦,可將資料賦值放到setData()中
public CharAdapter(Context context, List<String> datas)
{
mInflater = LayoutInflater.from(context);
mDatas = datas;
}
@Override
//檢視快取建立
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
//檢視快取,在ViewHolder構造時獲取檢視控制元件
MyViewHolder holder = new MyViewHolder(mInflater.inflate(
R.layout.item_char, parent, false));
return holder;
}
@Override
//檢視快取的資料繫結
public void onBindViewHolder(final MyViewHolder holder, final int position)
{
holder.tv.setText(mDatas.get(position));
// 如果設定了回撥,則設定點選事件
if (mOnItemClickLitener != null)
{
holder.itemView.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
int pos = holder.getPosition();
//儘量在回撥時處理邏輯,此處不進行處理,增加Adapter複用的可能
mOnItemClickLitener.onItemClick(holder.itemView, pos);
}
});
holder.itemView.setOnLongClickListener(new OnLongClickListener()
{
@Override
public boolean onLongClick(View v)
{
int pos = holder.getPosition();
//儘量在回撥時處理邏輯,此處不進行處理,增加Adapter複用的可能
mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
return false;
}
});
}
}
@Override
public int getItemCount()
{
return mDatas.size();
}
//需要自己定義,新增資料後需要呼叫notifyItemInserted(position),效果類似於ListView的notifyDataSetChanged()
//但是這裡會呼叫預設或者自定義的增加item動畫
public void addData(int position)
{
mDatas.add(position, "Insert One");
notifyItemInserted(position);
}
//需要自己定義,新增資料後需要呼叫notifyItemRemoved(position),效果類似於ListView的notifyDataSetChanged()
//但是這裡會呼叫預設或者自定義的刪除item動畫
public void removeData(int position)
{
mDatas.remove(position);
notifyItemRemoved(position);
}
//檢視快取
class MyViewHolder extends ViewHolder
{
TextView tv;
//在構造方法中獲取控制元件
public MyViewHolder(View view)
{
super(view);
tv = (TextView) view.findViewById(R.id.id_num);
}
}
}
4.佈局
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}" >
<android.support.v7.widget.RecyclerView
android:id="@+id/id_recyclerview"
android:divider="#ffff0000"
android:dividerHeight="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
item_char.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/item_bg"
android:layout_margin="2dp"
android:gravity="center"
>
<TextView
android:id="@+id/id_num"
android:layout_width="100dp"
android:layout_gravity="center"
android:layout_height="100dp"
android:gravity="center" />
</RelativeLayout>
5.瀑布流
在Adpater裡面修改一下每個item的寬高,RecyclerView的LayoutManager再換成
mLlayoutmanager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
mGlayoutmanager = new StaggeredGridLayoutManager(5,StaggeredGridLayoutManager.HORIZONTAL);
就能看到瀑布流的效果啦。
6.總結與demo下載
這其實是一個十分簡單的demo,你可以在此基礎上去修改RecyclerView的分隔線以及載入刪除動畫。
RecyclerView的強大之處就是解耦,以往常常將所有的程式碼,分隔線、動畫、邏輯處理、檢視快取等都放在Adapter中而導致Adapter根本無法複用。相信在大型專案中RecyclerView會有很好的表現以及程式設計體驗。
demo下載
注意:本demo有一處疏漏,需要在Manifest.xml中對對應需要 橫豎屏切換 的Activity新增一條屬性:
android:configChanges="orientation"