一、核心思想
根據Adapter的getItemViewType( )返回結果的不同來返回我們的item數量、ViewHolder.
二、代碼
(1)MainActivity布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
(2)item布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:background="#ff33b5e5"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center"
tools:text="別看了,我就是一個TextView" />
</RelativeLayout>
(3)Header和Footer的布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@android:color/holo_orange_light"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center"
android:text="我是頭布局" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:background="@android:color/holo_orange_light"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center"
android:text="我是腳布局" />
</RelativeLayout>
(4)MainActivity中
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private MainAdapter mAdapter;
private List<String> mDatas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
mAdapter = new MainAdapter(this,mDatas);
mRecyclerView.setAdapter(mAdapter);
//添加Header和Footer
addHeader();
addFooter();
}
private void addHeader() {
View v = LayoutInflater.from(this).inflate(R.layout.item_header, mRecyclerView, false);
mAdapter.setHeaderView(v);
}
private void addFooter() {
View v = LayoutInflater.from(this).inflate(R.layout.item_footer, mRecyclerView, false);
mAdapter.setFooterView(v);
}
private void initData() {
mDatas = new ArrayList<>();
for (int i = 'A'; i < 'Z'; i++) {
mDatas.add("" + (char) i);
}
}
}
(6)MainAdapter 中
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.MyViewHolder> {
private Context mContext;
private List<String> mDatas;
//定義三種類型來對應我們的Header、正常布局、Footer
public static final int TYPE_HEADER = 0;
public static final int TYPE_NORMAL = 1;
public static final int TYPE_FOOTER = 2;
private View mHeaderView;
private View mFooterView;
public MainAdapter(Context context, List<String> mDatas) {
this.mContext = context;
this.mDatas = mDatas;
}
public void setHeaderView(View headerView) {
mHeaderView = headerView;
notifyItemInserted(0);//注意這里
}
public View getHeaderView() {
return mHeaderView;
}
public void setFooterView(View footerView) {
mFooterView = footerView;
notifyItemInserted(getItemCount()-1);//注意這里
}
public View getFooterView() {
return mFooterView;
}
/**
* 重寫了getItemViewType方法,根據位置返回不同的ViewType
*/
@Override
public int getItemViewType(int position) {
if (mHeaderView == null && mFooterView == null) {
return TYPE_NORMAL;
}
if (position == 0) {
return TYPE_HEADER;
}
if (position == getItemCount() - 1) {
return TYPE_FOOTER;
}
return TYPE_NORMAL;
}
/**
* 根據不同的ViewType返回不同的item數量
*/
@Override
public int getItemCount() {
if(mHeaderView == null && mFooterView == null){
return mDatas.size();
}else if(mHeaderView == null && mFooterView != null){
return mDatas.size() + 1;
}else if (mHeaderView != null && mFooterView == null){
return mDatas.size() + 1;
}else {
return mDatas.size() + 2;
}
}
/**
* 根據不同的ViewType創建不同的ViewHolder對象
*/
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(mHeaderView != null && viewType == TYPE_HEADER) {
return new MyViewHolder(mHeaderView);
}
if(mFooterView != null && viewType == TYPE_FOOTER){
return new MyViewHolder(mFooterView);
}
return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_layout, parent, false));
}
@Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
if (getItemViewType(position) == TYPE_HEADER) {
return;
} else if (getItemViewType(position) == TYPE_FOOTER) {
return;
} else if (getItemViewType(position) == TYPE_NORMAL) {
if (mHeaderView == null) {
holder.tv.setText(mDatas.get(position));
} else {
holder.tv.setText(mDatas.get(position - 1));
}
}
}
/**
* 這里Header和Footer很簡單,就不單獨為Header和Footer創建一個ViewHolder了
*/
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv;
public MyViewHolder(View view) {
super(view);
if (itemView == mHeaderView){
return;
}
if (itemView == mFooterView){
return;
}
tv = (TextView)itemView.findViewById(R.id.tv);
}
}
}
三、效果圖
四、GridLayoutManager添加Header和Footer
我們在MainActivity中把LinearLayoutManager換成GridLayoutManager看一看效果
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));
//mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
//默認的分隔線不再適應GridLayoutManager了,這里注釋掉
Header和Footer竟然和普通item跑到一排了......
此時:要用到GridLayoutManager的一個方法setSpanSizeLookup:
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return 0;
}
});
這個方法需要一個SpanSizeLookup對象,SpanSizeLookup是一個定義在GridLayoutManager中抽象類,只有一個抽象方法getSpanSize(),
這個方法的返回值決定了我們每個position上的item占據的單元格個數.
正常情況下每個item占據1個單元格,結合GridLayoutManager構造方法中設置的每行的個數new GridLayoutManager(this, 2), 如果當前位置是Header和Footer的話,那么該item占據2個單元格,.
ok,了解了這個方法的話就可以來解決問題了
在Adapter中重寫onAttachedToRecyclerView()方法:
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager){
final GridLayoutManager gridManager = ((GridLayoutManager) layoutManager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (getItemViewType(position) == TYPE_HEADER){
return gridManager.getSpanCount();
}else if (getItemViewType(position) == TYPE_FOOTER){
return gridManager.getSpanCount();
}else{
return 1;
}
}
});
}
}
在來看一看效果:
ok,完美解決
五、StaggeredGridLayoutManager添加Header和Footer
在StaggeredGridLayoutManager中并沒有像GridLayoutManager中這樣的方法,這里可以通過StaggeredGridLayoutManager.LayoutParams的一個方法setFullSpan(boolean fullSpan)來設置占領全部空間.
同樣:
在Adapter中重寫onViewAttachedToWindow()方法:
@Override
public void onViewAttachedToWindow(MyViewHolder holder) {
super.onViewAttachedToWindow(holder);
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
if( lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams ) {
StaggeredGridLayoutManager.LayoutParams params =(StaggeredGridLayoutManager.LayoutParams) lp;
if(holder.getItemViewType()==TYPE_HEADER || holder.getItemViewType()==TYPE_FOOTER){
params.setFullSpan(true);
}else{
params.setFullSpan(false);
}
}
}
ok,解決了.