昨天一哥们熊sir要早睡早起用到了
RecyclerView
说要达到多布局的效果,然后他提到了GridLayoutManager
来实现,发现跟以往的常规的多布局有一点点不同,还是蛮有意思的。ToolBar+DrawerLayout使用
Android 自定义侧滑菜单效果(ViewDragHelper)
一站式CoordinatorLayout+ToolBar联动使用
1、进入正文
-
LinearLayoutManager
线性布局管理器,支持横向、纵向(效果相当于ListView的效果)。 -
GridLayoutManager
网格布局管理器。 -
StaggeredGridLayoutManager
瀑布流式布局管理器。
现在就是准备用GridLayoutManager
来协助完成多布局。
2、旧事重提
老规矩还是在AS的build.gradle中添加依赖,然后同步一下就可以引入依赖包:
compile 'com.android.support:recyclerview-v7:24.1.0'
效果展示
3、搞布局
把需要的布局罗列一下:
- 一个主界面Activity的布局文件命名为
activity_rvmoretype.xml
- 两种item样式,分成两个布局文件,标题的布局
item_rvmoretype_title.xml
,内容的布局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>
上面每个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>
布局都有了接下来就是常规的使用Recyclerview
了。
4、撸代码
用到了Json数据就要来一串Json数据和一个实体类。
{
"data":[
{
"isTitle":"1",
"content":"标题一取啥名",
"price":""
},
{
"isTitle":"0",
"content":"内容1",
"price":"100"
},
{
"isTitle":"0",
"content":"内容2",
"price":"100"
},
{
"isTitle":"0",
"content":"内容3",
"price":"100"
},
{
"isTitle":"0",
"content":"内容4",
"price":"100"
},
{
"isTitle":"0",
"content":"内容5",
"price":"100"
},
{
"isTitle":"0",
"content":"内容6",
"price":"100"
},
{
"isTitle":"0",
"content":"内容7",
"price":"100"
},
{
"isTitle":"1",
"content":"标题二取啥名",
"price":""
},
{
"isTitle":"0",
"content":"内容1",
"price":"100"
},
{
"isTitle":"0",
"content":"内容2",
"price":"100"
},
{
"isTitle":"0",
"content":"内容3",
"price":"100"
},
{
"isTitle":"0",
"content":"内容4",
"price":"100"
},
{
"isTitle":"0",
"content":"内容5",
"price":"100"
},
{
"isTitle":"0",
"content":"内容6",
"price":"100"
},
{
"isTitle":"0",
"content":"内容7",
"price":"100"
}
]
}
字符串有了可以整个实体类了命名ContentModel
:
/**
* Created by Leogh on 2017/9/7.
*/
public class ContentModel {
/**
* isTitle : 1
* content : 标题一取啥名
* 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;//标题标识
private int CONTENT_VIEW = 2;//内容标识
private SparseBooleanArray sparseBooleanArray = null;//缓存选中过的position
public MoreTypeAdapter(ContentModel mDatas, Context mContext) {
this.mDatas = mDatas;
this.mContext = mContext;
sparseBooleanArray = new SparseBooleanArray();
}
/**
* 根据getItemViewType中返回的布局标识确定布局
* @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;
}
/**
* 绑定数据
* @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();
}
/**
* 根据数据判断使用什么样的布局
* @param position
* @return 布局标识
*/
@Override
public int getItemViewType(int position) {
if ("1".equals(mDatas.getData().get(position).getIsTitle())) {//标题
return TITLE_VIEW;
} else if ("0".equals(mDatas.getData().get(position).getIsTitle())) {//内容
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\":\"标题一取啥名\",\"price\":\"\"},{\"isTitle\":\"0\",\"content\":\"内容1\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容2\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容3\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容4\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容5\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容6\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容7\",\"price\":\"100\"},{\"isTitle\":\"1\",\"content\":\"标题二取啥名\",\"price\":\"\"},{\"isTitle\":\"0\",\"content\":\"内容1\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容2\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容3\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容4\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容5\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容6\",\"price\":\"100\"},{\"isTitle\":\"0\",\"content\":\"内容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;//内容占一列
}
}
});
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, "你都没有选 也想点我?", Toast.LENGTH_SHORT).show();
}
}
}
}
注意了:(看黑板 这个是重点要考)
相对于正常的多布局,GridLayoutManager多布局这个时候就用了不一样的方式,在setSpanSizeLookup
来决定你的item要跨几列显示,标题当然是跨两列,内容只占一个位置。
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (adapter.getItemViewType(position) == 1) {
return 2;//title占两列
} else {
return 1;//内容占一列
}
}
});
等一下,忘记贴分割线的东西了:
/**
* 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) {//内容item才加底部边距
outRect.bottom = mDistance;
}
outRect.right = mDistance;
outRect.left = mDistance;
}
/**
* dp转px
*/
private int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
记录完了,收工