Android RecyclerView: Super Fast ListView 超級快速的Lis

Android RecyclerView: Super Fast ListView

原文來自個人微信公衆號: longkai_1991java

先上圖,看效果:node

img

前幾天剛release完公司的一個項目,有了點時間,因而就想找一些有意思的東西學習一下,順便運用在項目之中。看到iOS的同事們在談論iOS8的xx特性時,我忽然也有想在公司項目的下一個版本中添加Android L版本的特性。android

六月底的時候收看Google io時,當時對Android新的設計語言,Material Design,沒什麼太大的好感,感受色彩一坨一坨的,好難看的樣子,當時以爲亮點就是新的ART運行時環境和一些酷炫的動畫效果。再後來,8月初的時候,本身出於好奇真的拿Nexus 5安裝了一個L的預覽版,體驗不好...好多軟件都仍是holo的,反正以爲不是很期待就是啦。json

回到重點,下載好最新的SDK,你會發如今ANDROID_HOME/extras/android/m2repository/com/android/support下面多了很多兼容庫,cardview, support-annotations, recyclerview-v7,眼前一亮吧~這回,Google真的是拿出了好多東西呀,贊,尤爲是cardview和recyclerview這兩個新的控件,這個在Google最新的Material Design主頁上有說明和簡單的介紹,簡而言之,cardview能夠提供和Google不少自家應用觀感一致的卡片化佈局,而recyclerview則是一個加強版的listview,更強大和好用。微信

手癢了,特別想試試,可是這裏有一個坑,由於仍舊是預覽版,因此Google把minSDKVersion設置成了L,意思就是隻有使用L預覽版系統的機器才能夠測試。呵呵,廣大人民羣衆怎麼會被這個給嚇到,網上有在AndroidManifest.xml中設置<uses-sdk tools:node="replace" />便可。還有另外一招,將源碼解壓出來,而後本身按照項目結構放置源碼文件,最後再在本身的項目中引入就行了,可是要注意一點,須要把L版本相關的代碼給刪掉,無所謂啦,反正到時候Google推出正式版的。app

廢話扯了那麼多,下面纔是今天的主題,super fast listview,歷來沒有見過這樣快的list,甚至還支持橫向的滾動,要知道,這在以前的Android,要實現橫向的list是有多蛋疼!還有更多的驚喜,在另外一個兼容庫leanback-v17中,還有Grid,StagedGrid,HorizonalGrid等更高級的Widget,知道Pinterest的瀑布流麼?ide

下面的代碼,提供了滑動到底部自動加載更多的功能,是我本身根據之前listview的經驗寫的,因爲加載的速度過快,在刪除加載更多的提示時,有時會出現頁面有一部分空白間距的問題,沒辦法,只好postdelay 50毫秒,再將加載回來的list追加到末尾。佈局

下面是源代碼,使用recycle view配合card view實現無限list(自動帶提示加載更多,而且包含不用類型的view),super fast~ 看這段代碼前但願你能先去Material Design的主頁看看基本介紹和範例代碼。post

MainActivity.java學習

/*
 * Copyright (c) 2014 longkai
 * The software shall be used for good, not evil.
 */

package com.example.gridlayout;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.manuelpeinado.refreshactionitem.RefreshActionItem;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class MainActivity extends Activity {
  public static final String TAG = MainActivity.class.getSimpleName();

  public static final String TYPE = "type";
  public static final int ITEM = 0;
  public static final int SIMPLE = 1;
  public static final int FOOTER = 2;

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
      try {
        getFragmentManager().beginTransaction()
            .replace(android.R.id.content, CardFragment.class.newInstance())
            .commit();
      } catch (InstantiationException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }
    }
  }

  @Override public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  @Override public boolean onMenuItemSelected(int featureId, MenuItem item) {
    switch (item.getItemId()) {
      case R.id.action_settings:
        break;
      default:
        break;
    }
    return super.onMenuItemSelected(featureId, item);
  }

  public static class CardFragment extends Fragment {

    boolean loading = false;

    Handler mHandler = new Handler();
    RecyclerView mRecyclerView;
    CardAdapter mAdapter;

    @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View view = inflater.inflate(R.layout.recycler, container, false);
      mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler);
      return view;
    }

    @Override public void onViewCreated(View view, Bundle savedInstanceState) {
      super.onViewCreated(view, savedInstanceState);
    }

    @Override public void onActivityCreated(Bundle savedInstanceState) {
      super.onActivityCreated(savedInstanceState);
      List<JSONObject> list = new ArrayList<>();
      try {
        for (int i = 0; i < 300; i++) {
          JSONObject jsonObject = new JSONObject();
          if (i % 10 == 0) {
            jsonObject.put(TYPE, SIMPLE);
          } else {
            jsonObject.put(TYPE, ITEM);
          }
          list.add(jsonObject);
        }
      } catch (JSONException ignore) {
      }
      mAdapter = new CardAdapter(list);
      mRecyclerView.setHasFixedSize(true);
      mRecyclerView.setAdapter(mAdapter);
      LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
      layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
      mRecyclerView.setLayoutManager(layoutManager);
      mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override public void onScrollStateChanged(int newState) {

        }

        @Override public void onScrolled(int dx, int dy) {
          if (!loading && layoutManager.findLastVisibleItemPosition() == list.size() - 1) {
            loading = true;
            JSONObject jsonObject = new JSONObject();
            try {
              jsonObject.put(TYPE, FOOTER);
            } catch (JSONException ignore) {
            }
            mAdapter.add(jsonObject);
            new Thread(() -> {
              try {
                TimeUnit.SECONDS.sleep(3);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
              List<JSONObject> tmp = new ArrayList<JSONObject>();
              for (int i = 0; i < 10; i++) {
                JSONObject json = new JSONObject();
                try {
                  json.put(TYPE, ITEM);
                } catch (JSONException e) {
                }
                tmp.add(json);
              }
              mHandler.post(() -> {
                mAdapter.remove(mAdapter.getItemCount() - 1);
                mAdapter.addAll(tmp);
                loading = false;
              });
            }).start();
          }
        }
      });
    }
  }

  private static class CardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private List<JSONObject> list;

    private CardAdapter(List<JSONObject> list) {
      this.list = list;
    }

    @Override public int getItemCount() {
      return list.size();
    }

    @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      switch (viewType) {
        case SIMPLE:
          return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false)) {
          };
        case FOOTER:
          return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.load_more, parent, false)) {
          };
        default:
        case ITEM:
          View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card, parent, false);
          CardViewHolder holder = new CardViewHolder(view);
          return holder;
      }
    }

    @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
      switch (list.get(position).optInt(TYPE)) {
        case ITEM:
          CardViewHolder cardViewHolder = (CardViewHolder) holder;
          cardViewHolder.textView.setText("item " + position);
          break;
        case SIMPLE:
          TextView txt = (TextView) holder.itemView.findViewById(android.R.id.text1);
          txt.setText("simple txt!");
          Log.d(TAG, "simple text");
          break;
        case FOOTER:
          Log.d(TAG, "footer!");
          break;
      }
    }

    @Override public int getItemViewType(int position) {
      return list.get(position).optInt(TYPE);
    }

    public void add(JSONObject jsonObject) {
      this.list.add(jsonObject);
      notifyItemInserted(list.size() - 1);
    }

    public void addAll(List<JSONObject> list) {
      this.list.addAll(list);
      notifyDataSetChanged();
    }

    public void remove(int i) {
      list.remove(i);
      notifyItemRemoved(i);
    }

    static class CardViewHolder extends RecyclerView.ViewHolder {
      TextView textView;

      CardViewHolder(View view) {
        super(view);
        textView = (TextView) view.findViewById(R.id.txt);
      }
    }
  }
}

如下是佈局文件,很是簡單

card.xml

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    style="@style/CardView.Light"
    card_view:cardCornerRadius="4dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

  <TextView
      android:id="@+id/txt"
      android:textAppearance="?android:textAppearanceMedium"
      android:gravity="center"
      android:layout_width="match_parent"
      android:layout_height="200dp" />
</android.support.v7.widget.CardView>

recycler.xml

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recycler"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

最後附一張效果圖,比較醜,只是爲了演示而已

simple

因爲是公司的項目,因此比較詳細的代碼沒有貼出來,可是也是依據這段代碼弄出來的,有時間的話,改天封裝一個出來~


by longkai on 1 Sep. in Sz.

相關文章
相關標籤/搜索