去年很早之前,我就講解過RecyclerView的使用,今天我們就在講解CardView的時候,順便再把RecyclerView同時講解一下。RecyclerView、CardView為用于顯示復(fù)雜視圖的新增Widget。接下來看看如何使用吧。
RecyclerView
RecyclerView介紹
RecyclerView作為替代ListView使用,它更先進,更靈活,RecyclerView標準化了ViewHolder,ListView中convertView是復(fù)用的,在RecyclerView中,是把ViewHolder作為緩存的單位了,然后convertView作為ViewHolder的成員變量保持在ViewHolder中,也就是說,假設(shè)手機屏幕可顯示10個條目,則會創(chuàng)建10個ViewHolder緩存起來,每次復(fù)用的是ViewHolder,所以他把getView這個方法變?yōu)榱薿nCreateViewHolder。 ViewHolder更適合多種子布局的列表,尤其IM聊天對話框列表。
注意的是:RecyclerView不提供ListView中的setOnItemClickListener方法,我們可以在ViewHolder中添加類似的點擊事件。
RecyclerView注意事項,如何用
雖然RecyclerView充分考慮了它的擴展性,更好用,更靈活,但是用起來也有些麻煩。所以要使用RecyclerView,要好好考慮以下幾點:
- RecyclerView.Adapter:RecyclerView.Adapter包含了一種新型適配器,其實與以前我們使用的適配器基本類似,只是稍微有所不同,比如viewholder它幫我們封裝好了,不用像以前使用listview的適配器一樣自己去寫viewholder了。所以它的性能比以前應(yīng)該好了不少。
- LayoutManager:這個LayoutManager類決定視圖被放在畫面中哪個位置,但這只是它的眾多職責(zé)之一。它可以管理滾動和循環(huán)利用。LayoutManager是一個抽象類,好在系統(tǒng)提供了3個實現(xiàn)類:
1、LinearLayoutManager 現(xiàn)行管理器,支持橫向、縱向。
2、GridLayoutManager 網(wǎng)格布局管理器
3、 StaggeredGridLayoutManager 瀑布就式布局管理器 - ItemAnimator:ItemAnimator簡單來說是會根據(jù)適配器上收到的相關(guān)通知去動畫的顯示組件的修改,添加和刪除等。它會自動添加和移除item的動畫。自帶的默認效果也不錯,已經(jīng)非常好了。
如何用呢?這里我就不過多介紹了,因為關(guān)于RecyclerView的使用,去年我很早時間就寫過一篇文章。建議大家參考:
http://mp.weixin.qq.com/s?__biz=MjM5NDkxMTgyNw==&mid=208467006&idx=1&sn=c29971b395611008319222eaffad4f31#rd
RecyclerView上拉更多
RecyclerView具體使用不講了,今天我們順便講一下如何在RecyclerView加上拉更多的效果吧,下拉刷新我們使用SwipeRefreshLayout的效果就行。因為我看市面上目前大部分的app都是這樣做的,下拉刷新用SwipeRefreshLayout的效果,自己在RecyclerView上添加上拉更多。
很可惜的是,RecyclerView并沒有像ListView那樣提供給我們addFooterView()那樣的方法,那該如何實現(xiàn)呢?前面我們介紹RecyclerView時,說過RecyclerView適合多種嵌套的布局效果, ViewHolder更適合多種子布局的列表。所以我們看 RecyclerView的Adapter中的一個方法如下:
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType)
看到viewType了吧,就是在這里處理多種布局效果,上拉更多的布局和其他item其實沒有什么區(qū)別。所以處理方式大家都知道了吧。
- 第一步:添加布局狀態(tài)標識,并增加一項FooterView
在adapter中聲明布局狀態(tài)標識,是普通布局還是foot布局
private static final int TYPE_NORMAL_ITEM = 0; //普通Item
private static final int TYPE_FOOTER_ITEM = 1; //底部FooterView
在getItemCount()中加1
@Override
public int getItemCount() {
//+1是加入底部的加載布局項
?return list.size() + 1;
}
- 第二步:重寫getItemViewType判斷不同布局
public int getItemViewType(int position) {
// 如果position+1等于整個布局所有數(shù)總和就是底部布局
if (position + 1 == getItemCount()) {
return TYPE_FOOTER_ITEM;
?} else {
return TYPE_NORMAL_ITEM;
}
}
- 第三步:在onCreateViewHolder根據(jù)viewType返回不同的布局
//創(chuàng)建新View,被LayoutManager所調(diào)用
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
//如果viewType是普通item返回普通的布局,否則是底部布局并返回
if (viewType == TYPE_NORMAL_ITEM) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout
.cardview_recyclerview_item, viewGroup, false);
final NormalItmeViewHolder vh = new NormalItmeViewHolder(view);
if (mClickListener != null) {
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mClickListener.onItemClick(vh.itemView, vh.getLayoutPosition());
}
});
}
return vh;
} else {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout
.recyclerview_footer_view, viewGroup, false);
FooterViewHolder vh = new FooterViewHolder(view);
return vh;
}
}
- 第四步:根據(jù)holder類型判斷數(shù)據(jù)
//將數(shù)據(jù)與界面進行綁定的操作
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof NormalItmeViewHolder) {
((NormalItmeViewHolder) viewHolder).titleTv.setText(list.get(position).getTitle());
((NormalItmeViewHolder) viewHolder).contentTv.setText(list.get(position).getContent());
} else if (viewHolder instanceof FooterViewHolder) {
FooterViewHolder footViewHolder = (FooterViewHolder) viewHolder;
switch (load_more_status) {
case PULLUP_LOAD_MORE:
footViewHolder.foot_view_item_tv.setVisibility(View.VISIBLE);
footViewHolder.foot_view_item_tv.setText("上拉加載更多");
footViewHolder.pb.setVisibility(View.GONE);
break;
case LOADING_MORE:
footViewHolder.foot_view_item_tv.setVisibility(View.GONE);
footViewHolder.pb.setVisibility(View.VISIBLE);
break;
}
}
}
到這里,關(guān)于上拉更多基本就配置完了。一會完整adapter我會貼出來的。先看效果圖,如下:
Adapter的全部代碼如下:
public class PullMoreRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_NORMAL_ITEM = 0; //普通Item
private static final int TYPE_FOOTER_ITEM = 1; //底部FooterView
//上拉加載更多
public static final int PULLUP_LOAD_MORE = 1;
//正在加載中
public static final int LOADING_MORE = 2;
//默認為0
private int load_more_status = 0;
public List<CardInfo> list;
private OnItemClickListener mClickListener;
public PullMoreRecyclerAdapter(List<CardInfo> list) {
this.list = list;
}
//創(chuàng)建新View,被LayoutManager所調(diào)用
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
//如果viewType是普通item返回普通的布局,否則是底部布局并返回
if (viewType == TYPE_NORMAL_ITEM) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout
.cardview_recyclerview_item, viewGroup, false);
final NormalItmeViewHolder vh = new NormalItmeViewHolder(view);
if (mClickListener != null) {
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mClickListener.onItemClick(vh.itemView, vh.getLayoutPosition());
}
});
}
return vh;
} else {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout
.recyclerview_footer_view, viewGroup, false);
FooterViewHolder vh = new FooterViewHolder(view);
return vh;
}
}
//將數(shù)據(jù)與界面進行綁定的操作
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof NormalItmeViewHolder) {
((NormalItmeViewHolder) viewHolder).titleTv.setText(list.get(position).getTitle());
((NormalItmeViewHolder) viewHolder).contentTv.setText(list.get(position).getContent());
} else if (viewHolder instanceof FooterViewHolder) {
FooterViewHolder footViewHolder = (FooterViewHolder) viewHolder;
switch (load_more_status) {
case PULLUP_LOAD_MORE:
footViewHolder.foot_view_item_tv.setVisibility(View.VISIBLE);
footViewHolder.foot_view_item_tv.setText("上拉加載更多");
footViewHolder.pb.setVisibility(View.GONE);
break;
case LOADING_MORE:
footViewHolder.foot_view_item_tv.setVisibility(View.GONE);
footViewHolder.pb.setVisibility(View.VISIBLE);
break;
}
}
}
@Override
public int getItemCount() {
//+1是加入底部的加載布局項
return list.size() + 1;
}
public int getItemViewType(int position) {
// 如果position+1等于整個布局所有數(shù)總和就是底部布局
if (position + 1 == getItemCount()) {
return TYPE_FOOTER_ITEM;
} else {
return TYPE_NORMAL_ITEM;
}
}
//自定義的ViewHolder,持有每個Item的的所有界面元素
public static class NormalItmeViewHolder extends RecyclerView.ViewHolder {
public TextView titleTv, contentTv;
public ImageView iv;
public NormalItmeViewHolder(View view) {
super(view);
titleTv = (TextView) view.findViewById(R.id.item_title_tv);
contentTv = (TextView) view.findViewById(R.id.item_content_tv);
iv = (ImageView) view.findViewById(R.id.item_iv);
}
}
/**
* 底部FooterView布局
*/
public static class FooterViewHolder extends RecyclerView.ViewHolder {
public TextView foot_view_item_tv;
public ProgressBar pb;
public FooterViewHolder(View view) {
super(view);
pb = (ProgressBar) view.findViewById(R.id.progress_view);
foot_view_item_tv = (TextView) view.findViewById(R.id.tv_content);
}
}
public void setMoreStatus(int status){
load_more_status=status;
notifyDataSetChanged();
}
public void setOnItemClickListener(OnItemClickListener listener) {
mClickListener = listener;
}
public interface OnItemClickListener {
public void onItemClick(View itemView, int pos);
}
}
Activity中的代碼如下:
public class CardViewActivity extends BaseActivity {
private RecyclerView rv;
private SwipeRefreshLayout swipeRefreshWidget;
private PullMoreRecyclerAdapter adapter;
private LinearLayoutManager mLayoutManager;
List<CardInfo> list = new ArrayList<CardInfo>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_view);
rv = (RecyclerView) findViewById(R.id.rv);
swipeRefreshWidget = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_widget);
swipeRefreshWidget.setColorSchemeResources(R.color.colorAccent, R.color.add_bg_color, R
.color.colorPrimary, R.color.colorPrimaryDark, R.color.add_selected_color);
//創(chuàng)建默認的線性LayoutManager
mLayoutManager = new LinearLayoutManager(this);
rv.setLayoutManager(mLayoutManager);
//創(chuàng)建并設(shè)置Adapter
adapter = new PullMoreRecyclerAdapter(getDatas());
rv.setAdapter(adapter);
swipeRefreshWidget.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
swipeRefreshWidget.setEnabled(false);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
list.clear();
getDatas();
adapter.notifyDataSetChanged();
swipeRefreshWidget.setEnabled(true);
swipeRefreshWidget.setRefreshing(false);
}
}, 2000);
}
});
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
private int lastVisibleItem;
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 == adapter
.getItemCount()) {
adapter.setMoreStatus(PullMoreRecyclerAdapter.LOADING_MORE);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
getDatas();
adapter.setMoreStatus(PullMoreRecyclerAdapter.PULLUP_LOAD_MORE);
adapter.notifyDataSetChanged();
}
}, 2000);
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
lastVisibleItem = mLayoutManager.findLastVisibleItemPosition();
}
});
}
private List<CardInfo> getDatas() {
for (int i = 0; i < 10; i++) {
CardInfo ci = new CardInfo();
ci.setContent("美女說:非著名程序員公眾號是東半球最好的技術(shù)分享公眾號");
ci.setTitle("非著名程序員" + i);
list.add(ci);
}
return list;
}
}
CardView
CardView介紹
CardView是Android5.0之后為新增的控件,CardView是一個卡片布局,布局可以包含圓角和陰影,本質(zhì)上CardView是一個FrameLayout,因此它作為一個布局容器,可以布局其他的View。
CardView屬性
CardView中常用的屬性有:
- cardElevation:設(shè)置陰影的大小
- cardBackgroundColor:卡片布局的背景顏色
- cardCornerRadius:卡片布局的圓角的大小
- conentPadding:卡片布局和內(nèi)容之間的距離
效果圖和實例代碼
效果圖如下:
代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:layout_marginTop="12dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
app:cardBackgroundColor="@color/white"
app:contentPadding="8dp"
app:cardCornerRadius="10dp"
app:cardElevation="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/item_iv"
android:layout_width="120dp"
android:layout_height="90dp"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:background="@drawable/item_one"
android:scaleType="centerCrop"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginRight="10dp"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/item_title_tv"
android:layout_width="wrap_content"
android:textColor="#383838"
android:textSize="20sp"
android:textStyle="bold"
android:layout_height="wrap_content"
android:text="非著名程序員"/>
<TextView
android:id="@+id/item_content_tv"
android:textColor="#545454"
android:textSize="16sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="美女說:非著名程序員公眾號是東半球最好的技術(shù)分享公眾號"/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
最后友情提醒一下,使用CardView別忘了添加依賴:
compile 'com.android.support:cardview-v7:23.4.0'
demo的github地址:https://github.com/loonggg/MaterialDesignDemo 去star吧,我會慢慢完善的。