首页 > 代码库 > Android RecyclerView: Super Fast ListView 超级快速的Lis
Android RecyclerView: Super Fast ListView 超级快速的Lis
Android RecyclerView: Super Fast ListView
原文来自我的微信公众号: longkai_1991
先上图,看效果:
前几天刚release完公司的一个项目,有了点时间,于是就想找一些有意思的东西学习一下,顺便运用在项目之中。看到iOS的同事们在谈论iOS8的xx特性时,我突然也有想在公司项目的下一个版本中添加Android L版本的特性。
六月底的时候收看Google io时,当时对Android新的设计语言,Material Design,没什么太大的好感,感觉色彩一坨一坨的,好难看的样子,当时觉得亮点就是新的ART运行时环境和一些酷炫的动画效果。再后来,8月初的时候,自己出于好奇真的拿Nexus 5安装了一个L的预览版,体验很差…好多软件都还是holo的,反正觉得不是很期待就是啦。
回到重点,下载好最新的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推出正式版的。
废话扯了那么多,下面才是今天的主题,super fast listview,从来没有见过这样快的list,甚至还支持横向的滚动,要知道,这在之前的Android,要实现横向的list是有多蛋疼!还有更多的惊喜,在另一个兼容库leanback-v17
中,还有Grid,StagedGrid,HorizonalGrid等更高级的Widget,知道Pinterest的瀑布流麽?
下面的代码,提供了滑动到底部自动加载更多的功能,是我自己根据以前listview的经验写的,由于加载的速度过快,在删除加载更多的提示时,有时会出现页面有一部分空白间距的问题,没办法,只好postdelay 50毫秒,再将加载回来的list追加到末尾。
下面是源代码,使用recycle view配合card view实现无限list(自动带提示加载更多,并且包含不用类型的view),super fast~ 看这段代码前希望你能先去Material Design的主页看看基本介绍和范例代码。
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" />
最后附一张效果图,比较丑,只是为了演示而已
由于是公司的项目,所以比较详细的代码没有贴出来,但是也是依据这段代码弄出来的,有时间的话,改天封装一个出来~
by longkai on 1 Sep. in Sz.
Android RecyclerView: Super Fast ListView 超级快速的Lis