昨天一哥們熊sir要早睡早起用到了
RecyclerView
說要達(dá)到多布局的效果,然后他提到了GridLayoutManager
來實(shí)現(xiàn),發(fā)現(xiàn)跟以往的常規(guī)的多布局有一點(diǎn)點(diǎn)不同,還是蠻有意思的。ToolBar+DrawerLayout使用
Android 自定義側(cè)滑菜單效果(ViewDragHelper)
一站式CoordinatorLayout+ToolBar聯(lián)動(dòng)使用
1、進(jìn)入正文
-
LinearLayoutManager
線性布局管理器,支持橫向、縱向(效果相當(dāng)于ListView的效果)。 -
GridLayoutManager
網(wǎng)格布局管理器。 -
StaggeredGridLayoutManager
瀑布流式布局管理器。
現(xiàn)在就是準(zhǔn)備用GridLayoutManager
來協(xié)助完成多布局。
2、舊事重提
老規(guī)矩還是在AS的build.gradle中添加依賴,然后同步一下就可以引入依賴包:
compile 'com.android.support:recyclerview-v7:24.1.0'
效果展示
3、搞布局
把需要的布局羅列一下:
- 一個(gè)主界面Activity的布局文件命名為
activity_rvmoretype.xml
- 兩種item樣式,分成兩個(gè)布局文件,標(biāo)題的布局
item_rvmoretype_title.xml
,內(nèi)容的布局item_rvmoretype_content.xml
。
activity_rvmoretype.xml
如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_rvmoretype"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical"
android:fitsSystemWindows="true"
tools:context="com.sobergh.soberghalltest.widget.recyclerview.RVMoretypeActivity">
<include layout="@layout/top_bar"
android:id="@+id/toolbar"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_moretype"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="20dp"
android:overScrollMode="never"/>
<!--style為去掉陰影效果-->
<Button
android:id="@+id/btn_moretype_submit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_rvmoretype_btn"
android:layout_margin="5dp"
style="?android:attr/borderlessButtonStyle"
android:text="提交"/>
</LinearLayout>
item_rvmoretype_title.xml
如下:
<?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="50dp"
android:gravity="center"
android:minHeight="50dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_moretype_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="title"
android:textSize="20sp"/>
</LinearLayout>
item_rvmoretype_content.xml
如下:
<?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="30dp"
android:gravity="center"
android:minHeight="30dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_moretype_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="content"
android:background="@drawable/shape_homelist_location_normal"
android:textSize="18sp"
android:clickable="true"/>
</LinearLayout>
上面每個(gè)item都用到了選中與不選中背景也貼一下代碼:
非選中shape_homelist_location_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="15dp"/>
<stroke android:width="1dp" android:color="#E5E5E5"/>
<solid android:color="@android:color/white"/>
</shape>
選中shape_homelist_location_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="15dp"/>
<solid android:color="@android:color/white"/>
<stroke android:width="1dp" android:color="#5783EE"/>
</shape>
最后還有提交按鈕的背景selector_rvmoretype_btn.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/shape_homelist_location_pressed"/>
<item android:drawable="@drawable/shape_homelist_location_normal"/>
</selector>
布局都有了接下來就是常規(guī)的使用Recyclerview
了。
4、擼代碼
用到了Json數(shù)據(jù)就要來一串Json數(shù)據(jù)和一個(gè)實(shí)體類。
{
"data":[
{
"isTitle":"1",
"content":"標(biāo)題一取啥名",
"price":""
},
{
"isTitle":"0",
"content":"內(nèi)容1",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容2",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容3",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容4",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容5",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容6",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容7",
"price":"100"
},
{
"isTitle":"1",
"content":"標(biāo)題二取啥名",
"price":""
},
{
"isTitle":"0",
"content":"內(nèi)容1",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容2",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容3",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容4",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容5",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容6",
"price":"100"
},
{
"isTitle":"0",
"content":"內(nèi)容7",
"price":"100"
}
]
}
字符串有了可以整個(gè)實(shí)體類了命名ContentModel
:
/**
* Created by Leogh on 2017/9/7.
*/
public class ContentModel {
/**
* isTitle : 1
* content : 標(biāo)題一取啥名
* price :
*/
private List<DataBean> data;
public List<DataBean> getData() {
return data;
}
public void setData(List<DataBean> data) {
this.data = data;
}
public static class DataBean {
private String isTitle;
private String content;
private String price;
public String getIsTitle() {
return isTitle;
}
public void setIsTitle(String isTitle) {
this.isTitle = isTitle;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
}
既然用到了RecyclerView
那Adapter是少不了的了,解釋什么的一般就放在代碼里。
/**
* Created by Leogh on 2017/9/7.
*/
public class MoreTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private ContentModel mDatas = null;
private Context mContext;
private int TITLE_VIEW = 1;//標(biāo)題標(biāo)識(shí)
private int CONTENT_VIEW = 2;//內(nèi)容標(biāo)識(shí)
private SparseBooleanArray sparseBooleanArray = null;//緩存選中過的position
public MoreTypeAdapter(ContentModel mDatas, Context mContext) {
this.mDatas = mDatas;
this.mContext = mContext;
sparseBooleanArray = new SparseBooleanArray();
}
/**
* 根據(jù)getItemViewType中返回的布局標(biāo)識(shí)確定布局
* @param parent
* @param viewType
* @return
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder holder = null;
LayoutInflater inflater = LayoutInflater.from(mContext);
if (viewType == TITLE_VIEW) {
View view = inflater.inflate(R.layout.item_rvmoretype_title, parent, false);
holder = new TitleViewHolder(view);
} else {
View view = inflater.inflate(R.layout.item_rvmoretype_content, parent, false);
holder = new ContentViewHolder(view);
}
return holder;
}
/**
* 綁定數(shù)據(jù)
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof TitleViewHolder) {
((TitleViewHolder) holder).tv_title.setText(mDatas.getData().get(position).getContent());
} else if (holder instanceof ContentViewHolder){
((ContentViewHolder) holder).tv_content.setBackgroundResource(R.drawable.shape_homelist_location_normal);
((ContentViewHolder) holder).tv_content.setText(mDatas.getData().get(position).getContent());
((ContentViewHolder) holder).tv_content.setOnClickListener(new ClickItemListener(position));
}
}
@Override
public int getItemCount() {
return mDatas.getData().size();
}
/**
* 根據(jù)數(shù)據(jù)判斷使用什么樣的布局
* @param position
* @return 布局標(biāo)識(shí)
*/
@Override
public int getItemViewType(int position) {
if ("1".equals(mDatas.getData().get(position).getIsTitle())) {//標(biāo)題
return TITLE_VIEW;
} else if ("0".equals(mDatas.getData().get(position).getIsTitle())) {//內(nèi)容
return CONTENT_VIEW;
}
return super.getItemViewType(position);
}
public SparseBooleanArray getSelectedItemArray() {
return sparseBooleanArray;
}
class ClickItemListener implements View.OnClickListener{
private int currentPosition = -1;
public ClickItemListener(int currentPosition) {
this.currentPosition = currentPosition;
}
@Override
public void onClick(View v) {
if (currentPosition == -1) return;
if (sparseBooleanArray.get(currentPosition)) {
sparseBooleanArray.put(currentPosition, false);
v.setBackgroundResource(R.drawable.shape_homelist_location_normal);
} else {
sparseBooleanArray.put(currentPosition, true);
v.setBackgroundResource(R.drawable.shape_homelist_location_pressed);
}
}
}
class TitleViewHolder extends RecyclerView.ViewHolder {
TextView tv_title;
public TitleViewHolder(View itemView) {
super(itemView);
tv_title = (TextView) itemView.findViewById(R.id.tv_moretype_title);
}
}
class ContentViewHolder extends RecyclerView.ViewHolder {
TextView tv_content;
public ContentViewHolder(View itemView) {
super(itemView);
tv_content = (TextView) itemView.findViewById(R.id.tv_moretype_content);
}
}
}
接下來就是Activity了:
public class RVMoretypeActivity extends BaseActivity implements View.OnClickListener{
private RecyclerView rv_moretype = null;
private Button btn_moretype_submit = null;
private String jsonData = "";
private ContentModel bean = null;
private MoreTypeAdapter adapter = null;
//這是繼承了自己封裝的BaseActivity重寫的方法 直接改成OnCreate就能用了 在繼承一下Activity就行了
@Override
public void init() {
setContentView(R.layout.activity_rvmoretype);
initView();
initData();
operRecyclerView();
}
private void initData() {
String jsonStr = "{\"data\":[{\"isTitle\":\"1\",\"content\":\"標(biāo)題一取啥名\",\"price\":\"\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容1\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容2\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容3\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容4\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容5\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容6\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容7\",\"price\":\"100\"},{\"isTitle\":\"1\",\"content\":\"標(biāo)題二取啥名\",\"price\":\"\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容1\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容2\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容3\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容4\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容5\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容6\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"內(nèi)容7\",\"price\":\"100\"}]}";
Gson gson = new Gson();
bean = gson.fromJson(jsonStr, ContentModel.class);
}
private void operRecyclerView() {
adapter = new MoreTypeAdapter(bean, this);
rv_moretype.addItemDecoration(new ItemDistanceDecoration(this));
GridLayoutManager manager = new GridLayoutManager(this, 2);//兩列
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (adapter.getItemViewType(position) == 1) {
return 2;//title占兩列
} else {
return 1;//內(nèi)容占一列
}
}
});
rv_moretype.setLayoutManager(manager);
rv_moretype.setAdapter(adapter);
}
private void initView() {
rv_moretype = (RecyclerView) findViewById(R.id.rv_moretype);
btn_moretype_submit = (Button) findViewById(R.id.btn_moretype_submit);
btn_moretype_submit.setOnClickListener(this);
}
@Override
public String setTitle() {
return "Recyclerview多布局";
}
@Override
public void onClick(View v) {
if (v.getId() == btn_moretype_submit.getId()) {
if (adapter != null && adapter.getSelectedItemArray().size() > 0) {
String selectedItem = "";
SparseBooleanArray selectedItemArray = adapter.getSelectedItemArray();
for (int i = 0; i < bean.getData().size(); i++) {
if (selectedItemArray.get(i)) {
selectedItem += "第" + i;
}
}
Toast.makeText(mActivity, selectedItem, Toast.LENGTH_SHORT).show();
adapter.getSelectedItemArray().clear();
adapter.notifyDataSetChanged();
} else {
Toast.makeText(mActivity, "你都沒有選 也想點(diǎn)我?", Toast.LENGTH_SHORT).show();
}
}
}
}
注意了:(看黑板 這個(gè)是重點(diǎn)要考)
相對(duì)于正常的多布局,GridLayoutManager多布局這個(gè)時(shí)候就用了不一樣的方式,在setSpanSizeLookup
來決定你的item要跨幾列顯示,標(biāo)題當(dāng)然是跨兩列,內(nèi)容只占一個(gè)位置。
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (adapter.getItemViewType(position) == 1) {
return 2;//title占兩列
} else {
return 1;//內(nèi)容占一列
}
}
});
等一下,忘記貼分割線的東西了:
/**
* Created by Leogh on 2017/9/7.
*/
public class ItemDistanceDecoration extends RecyclerView.ItemDecoration {
private Context context;
private int mDistance = 20;
public ItemDistanceDecoration(Context context) {
this.context = context;
mDistance = dp2px(context, mDistance);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int s = parent.getChildAdapterPosition(view);
int sss = parent.getAdapter().getItemViewType(parent.getChildAdapterPosition(view));
if (parent.getAdapter().getItemViewType(parent.getChildAdapterPosition(view)) == 2) {//內(nèi)容item才加底部邊距
outRect.bottom = mDistance;
}
outRect.right = mDistance;
outRect.left = mDistance;
}
/**
* dp轉(zhuǎn)px
*/
private int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
記錄完了,收工