继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Android Study Material Design 二

一只名叫tom的猫
关注TA
已关注
手记 484
粉丝 62
获赞 330

本文目标

阅读完本文,你会get如下技能:

  • 使用RecyclerView实现复杂布局;

  • 使用RecyclerView实现ListView以及GirdView混排效果;

  • 通过优化Model加深了解通过RecyclerView实现混排效果。

希望通过不断get小技能,让你在Android路上一路畅通无堵~

废话不多说,开车~

一、使用RecyclerView实现复杂布局

首先我们先做一些基本操作,类似于控件放置,初始化(控件,模拟数据)等。

1.1 引用RecyclerView,填充布局

1)Android Studio的小伙伴记得引入有关RecyclerView依赖;
2)Eclipse的小伙伴记得拷贝本地SDK下载包含的RecyclerView jar包即可。

布局放置如下:

放置好了一个RecyclerView,下面模拟数据时,来一个Model类。

1.2 设置Model类

package com.materialdesignstudy.complexrecycler.itemone;/**
 * Created by HLQ on 2017/10/22
 */public class DataModel {    // 状态标识位
    public static final int TYPE_ONE = 1;    public static final int TYPE_TWO = 2;    public static final int TYPE_THREE = 3;    public int type; // 类型 针对某种样式文件 也就是布局
    public int avatarColor; // 头像颜色
    public String name; // 姓名
    public String content; // 内容
    public int contentColor; // 内容颜色}

1.3 定义item布局

如效果图一般,我们创建如下item布局文件:

item_type_one

item_type_two:

item_layout_three:

1.4 编写对应ViewHolder

由于我们的ViewHolder都需要构造以及数据绑定,由此,我们拓展一个封装ViewHolder类,让其他的ViewHolder直接集成此类即可。

定义封装ViewHolder类:

package com.materialdesignstudy.complexrecycler.itemone;import android.support.v7.widget.RecyclerView;import android.view.View;/**
 * ViewHolder封装类
 * Created by HLQ on 2017/10/22
 */public abstract class TypeAbstractViewHolder extends RecyclerView.ViewHolder {    public TypeAbstractViewHolder(View itemView) {        super(itemView);
    }    /**
     * 数据绑定
     *
     * @param dataModel 数据源 由于我们模拟数据实体类暂定为DataModel 这里直接传入这个即可
     *                  后期可根据项目实际需求去设置 也可以直接写为T
     */
    public abstract void bindHolder(DataModel dataModel);

}

定义Item1对应的ViewHolder:

package com.materialdesignstudy.complexrecycler.itemone;import android.graphics.Color;import android.view.View;import android.widget.ImageView;import android.widget.TextView;import com.materialdesignstudy.R;/**
 * Created by HLQ on 2017/10/22
 */public class TypeOneViewHolder extends TypeAbstractViewHolder {    public ImageView avatar;    public TextView name;    public TypeOneViewHolder(View itemView) {        super(itemView);        // 初始化控件
        avatar = itemView.findViewById(R.id.avatar);
        name = itemView.findViewById(R.id.name);        // 为了区分item 这里为item设置背景颜色
        itemView.setBackgroundColor(Color.YELLOW);
    }    @Override
    public void bindHolder(DataModel dataModel) {        // 数据绑定
        avatar.setBackgroundResource(dataModel.avatarColor);
        name.setText(dataModel.name);
    }

}

item2对应ViewHolder:

package com.materialdesignstudy.complexrecycler.itemone;import android.graphics.Color;import android.view.View;import android.widget.ImageView;import android.widget.TextView;import com.materialdesignstudy.R;/**
 * Created by HLQ on 2017/10/22
 */public class TypeTwoViewHolder extends TypeAbstractViewHolder {    public ImageView avatar;    public TextView name, content;    public TypeTwoViewHolder(View itemView) {        super(itemView);
        avatar = itemView.findViewById(R.id.avatar);
        name = itemView.findViewById(R.id.name);
        content = itemView.findViewById(R.id.content);
        itemView.setBackgroundColor(Color.GRAY);
    }    @Override
    public void bindHolder(DataModel dataModel) {
        avatar.setBackgroundResource(dataModel.avatarColor);
        name.setText(dataModel.name);
        content.setText(dataModel.content);
    }

}

item3对应ViewHolder:

package com.materialdesignstudy.complexrecycler.itemone;import android.graphics.Color;import android.view.View;import android.widget.ImageView;import android.widget.TextView;import com.materialdesignstudy.R;/**
 * Created by HLQ on 2017/10/22
 */public class TypeThreeViewHolder extends TypeAbstractViewHolder {    public ImageView avatar, contentImg;    public TextView name, content;    public TypeThreeViewHolder(View itemView) {        super(itemView);
        avatar = itemView.findViewById(R.id.avatar);
        name = itemView.findViewById(R.id.name);
        content = itemView.findViewById(R.id.content);
        contentImg = itemView.findViewById(R.id.contentImg);
        itemView.setBackgroundColor(Color.BLUE);
    }    @Override
    public void bindHolder(DataModel dataModel) {
        avatar.setBackgroundResource(dataModel.avatarColor);
        name.setText(dataModel.name);
        content.setText(dataModel.content);
        contentImg.setBackgroundResource(dataModel.contentColor);
    }

}

1.5 定义空的Adapter类,初始化控件、模拟数据

package com.materialdesignstudy.complexrecycler.itemone;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import com.materialdesignstudy.R;import java.util.ArrayList;import java.util.List;/**
 * 复杂布局实现
 * Created by HLQ on 2017/10/22
 */public class ComplexOneActivity extends AppCompatActivity {    private RecyclerView mRecyclerView;    private OneAdapter mOneAdapter;    private int mColor[] = {android.R.color.holo_red_light,
            android.R.color.holo_green_light,
            android.R.color.holo_blue_light};    @Override
    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_complec_one);
        initItem();
        initData();
    }    private void initData() {
        List dataList = new ArrayList<>();        for (int i = 0; i < 20; i++) {            int type = (int) ((Math.random() * 3) + 1); // 随机type
            DataModel dataModel = new DataModel();
            dataModel.avatarColor = mColor[type - 1];
            dataModel.type = type;
            dataModel.name = "name" + i;
            dataModel.content = "content:" + i;
            dataModel.contentColor = mColor[(type + 1) % 3];
            dataList.add(dataModel);
        }
        mOneAdapter.addList(dataList);
        mOneAdapter.notifyDataSetChanged();
    }    private void initItem() {
        mRecyclerView = findViewById(R.id.id_recy);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        mOneAdapter = new OneAdapter(this);
        mRecyclerView.setAdapter(mOneAdapter);
    }
}

以上这些都是很easy的,这里就不过多说明了。关键内容如下,让我们一起瞅瞅Adapter又是如何编写的。

1.6 打造属于you的Adapter

首先,这里需要再次说明一点:

  • getItemViewType():返回当前ItemView类型,而我们将会根据此类型进行相应的业务处理。

嗯那,就是这样,下面直接放出代码:

package com.materialdesignstudy.complexrecycler.itemone;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.ViewGroup;import com.materialdesignstudy.R;import java.util.ArrayList;import java.util.List;/**
 * Created by HLQ on 2017/10/22
 */public class OneAdapter extends RecyclerView.Adapter {    private LayoutInflater mLayoutInflater;    private List mDataList = new ArrayList<>();    public OneAdapter(Context context) {        this.mLayoutInflater = LayoutInflater.from(context);
    }    public void addList(List dataModelList) {        this.mDataList.addAll(dataModelList);
    }    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        // 通过获取不同的viewType,返回对应的ViewHolder以及引入的布局文件进行渲染,从而实现复杂布局实现
        switch (viewType) {            case DataModel.TYPE_ONE:                return new TypeOneViewHolder(mLayoutInflater.inflate(R.layout.item_type_one, parent, false));            case DataModel.TYPE_TWO:                return new TypeTwoViewHolder(mLayoutInflater.inflate(R.layout.item_type_two, parent, false));            case DataModel.TYPE_THREE:                return new TypeThreeViewHolder(mLayoutInflater.inflate(R.layout.item_type_three, parent, false));
        }        return null;
    }    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        // 由于子类ViewHolder继承自TypeAbstractViewHolder,这里可以直接通过强制转化去绑定数据
        // 这也是我们为什么要对ViewHolder进行封装的一点优势
        ((TypeAbstractViewHolder) holder).bindHolder(mDataList.get(position));
    }    @Override
    public int getItemCount() {        return mDataList.size();
    }    @Override
    public int getItemViewType(int position) {        return mDataList.get(position).type;
    }
}

到现在为止,我们已经完成了通过RecyclerView实现复杂布局,不信你可以运行下你现在的代码喽~

二、使用RecyclerView实现ListView以及GirdView混排效果

本小节内容主要关注于LayoutManager的setSpanSizeLookup()方法,下面对其进行简述。

> setSpanSizeLookup(): 主要使用这个方法来展示不同的 item 屏幕跨度 

> * spanCount:在创建 GridLayoutManager 对象的时候构造方法需要传入这个参数,也就是设置每行排列 item 个数。
><br/>
> * spanSize:在 setSpanSizeLookup() 方法中,这个方法返回的是当前位置的 item 跨度大小。

嗯哼,简单了解后,我们撸码呗`

package com.materialdesignstudy.complexrecycler.itemtwo;import android.graphics.Rect;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import com.materialdesignstudy.R;import com.materialdesignstudy.complexrecycler.itemone.DataModel;import com.materialdesignstudy.complexrecycler.itemone.OneAdapter;import java.util.ArrayList;import java.util.List;/**
 * 使用RecyclerView实现ListView+GridView混排效果
 * create by heliquan at 2017年10月23日
 * 重点关注setSpanSizeLookup即可 获取当前跨度
 */public class ComplexTwoActivity extends AppCompatActivity {    private RecyclerView mRecyclerView;    private OneAdapter mOneAdapter;    private int mColor[] = {android.R.color.holo_red_light,
            android.R.color.holo_green_light,
            android.R.color.holo_blue_light};    @Override
    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_complec_one);
        initItem();
        initData();
    }    private void initData() {
        List dataList = new ArrayList&lt;&gt;();        for (int i = 0; i &lt; 30; i++) {            // 模拟不同itemType
            int type;            if (i  15 && i &lt; 20)) {
                type = 1;
            } else if (i  20) {
                type = 2;
            } else {
                type = 3;
            }
            DataModel dataModel = new DataModel();
            dataModel.avatarColor = mColor[type - 1];
            dataModel.type = type;
            dataModel.name = "name" + i;
            dataModel.content = "content:" + i;
            dataModel.contentColor = mColor[(type + 1) % 3];
            dataList.add(dataModel);
        }
        mOneAdapter.addList(dataList);
        mOneAdapter.notifyDataSetChanged();
    }    private void initItem() {
        mRecyclerView = findViewById(R.id.id_recy);        // 更换显示布局样式为GirdLayoutManager
        final GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
        gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {            @Override
            public int getSpanSize(int position) {                // 获取当前位置下的ItemViewType
                int type = mRecyclerView.getAdapter().getItemViewType(position);                // 由于item1和item2可以正常显示 而item3需要横跨2列
                // 所以需要在这里对item3进行单独处理
                if (type == DataModel.TYPE_THREE) {                    return gridLayoutManager.getSpanCount(); // item3需要横跨2列
                } else {                    return 1;
                }
            }
        });
        mRecyclerView.setLayoutManager(gridLayoutManager);
        mOneAdapter = new OneAdapter(this);
        mRecyclerView.setAdapter(mOneAdapter);        // 为了显示效果更好 在此添加分割线
        mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
                GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams();                int spanSize = layoutParams.getSpanSize(); // 获取当前位置的 item 跨度大小
                int spanIndex = layoutParams.getSpanIndex(); // 获取每行排列 item 个数
                outRect.top = 20;                // 如果当前跨度不等于当前索引 表示当前不属于item3
                if (spanSize != gridLayoutManager.getSpanCount()) { // 针对item1,item2做分割线处理
                    if (spanIndex == 1) {
                        outRect.left = 10;
                    } else {
                        outRect.right = 10;
                    }
                }
            }
        });
    }
}

其实这部分的关键点就是在于那个方法,大家有时间可以细致了解。

好了,到现在为止,第二小节也over了。Nice。

三、复杂Model应对之策

以上俩点都是基于相同的Model,那么在实际开发中,我们Model也许各不相同,那么这时候该如何处理呢?

这里为大家提供下思路,可以顺着延伸下。

  • 改造ViewHolder封装类,之前我们直接采用固定Model,而今替换T即可,而对应子类ViewHolder继承时需要指定Model类型;

  • Adapter中却需要记录当前itemType对应包含List.size()以及itemType对应类型。原因在于我们需要将数据进行组合,因为后台的数据不可能会按照我们所想的来,只能进行二次拼接。

关键内容如上,下面就简单贴出关键代码,完整代码请在下方查看GitHub。

3.1 改造后的ViewHolder封装类

package com.materialdesignstudy.complexrecycler.itemthree;import android.support.v7.widget.RecyclerView;import android.view.View;import com.materialdesignstudy.complexrecycler.itemone.DataModel;/**
 * Created by HLQ on 2017/10/22
 */public abstract class TypeAbstractViewHolder extends RecyclerView.ViewHolder {    public TypeAbstractViewHolder(View itemView) {        super(itemView);
    }    public abstract void bindHolder(T dataModel);

}

3.2 改造后的数据初始化

    private void initData() {
        List oneList = new ArrayList&lt;&gt;();        for (int i = 0; i &lt; 10; i++) {
            DataModelOne dataModel = new DataModelOne();
            dataModel.name = "name" + i;
            dataModel.avatatColor = mColor[0];
            oneList.add(dataModel);
        }
        List twoList = new ArrayList&lt;&gt;();        for (int i = 0; i &lt; 10; i++) {
            DataModelTwo dataModel = new DataModelTwo();
            dataModel.name = "name" + i;
            dataModel.avatatColor = mColor[1];
            dataModel.content = "content:" + i;
            twoList.add(dataModel);
        }
        List threeList = new ArrayList&lt;&gt;();        for (int i = 0; i &lt; 10; i++) {
            DataModelThree dataModel = new DataModelThree();
            dataModel.name = "name" + i;
            dataModel.avatatColor = mColor[2];
            dataModel.content = "content:" + i;
            dataModel.contentColor = mColor[2];
            threeList.add(dataModel);
        }
        mOneAdapter.addList(oneList,twoList,threeList);
        mOneAdapter.notifyDataSetChanged();
    }

3.3 改造后的Adapter

package com.materialdesignstudy.complexrecycler.itemthree;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.ViewGroup;import com.materialdesignstudy.R;import com.materialdesignstudy.complexrecycler.itemone.DataModel;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/**
 * Created by HLQ on 2017/10/22
 */public class TwoAdapter extends RecyclerView.Adapter {    public static final int TYPE_ONE = 1;    public static final int TYPE_TWO = 2;    public static final int TYPE_THREE = 3;    private LayoutInflater mLayoutInflater;    private List mTypes = new ArrayList&lt;&gt;(); // 存放type
    private Map mPositions = new HashMap&lt;&gt;(); // 存放type下包含数据itemCount
    private List mOneList = new ArrayList&lt;&gt;();    private List mTwoList = new ArrayList&lt;&gt;();    private List mThreeList = new ArrayList&lt;&gt;();    public TwoAdapter(Context context) {        this.mLayoutInflater = LayoutInflater.from(context);
    }    public void addList(List oneList, List twoList, List threeList) {
        addListByType(TYPE_ONE, oneList);
        addListByType(TYPE_TWO, twoList);
        addListByType(TYPE_THREE, threeList);        this.mOneList = oneList;        this.mTwoList = twoList;        this.mThreeList = threeList;
    }    private void addListByType(int type, List list) {
        mPositions.put(type, mTypes.size());        for (int i = 0; i &lt; list.size(); i++) {
            mTypes.add(type);
        }
    }    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        switch (viewType) {            case DataModel.TYPE_ONE:                return new TypeOneViewHolder(mLayoutInflater.inflate(R.layout.item_type_one, parent, false));            case DataModel.TYPE_TWO:                return new TypeTwoViewHolder(mLayoutInflater.inflate(R.layout.item_type_two, parent, false));            case DataModel.TYPE_THREE:                return new TypeThreeViewHolder(mLayoutInflater.inflate(R.layout.item_type_three, parent, false));
        }        return null;
    }    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        int viewType = getItemViewType(position);        int realPosition = position - mPositions.get(viewType);        switch (viewType) {            case DataModel.TYPE_ONE:
                ((TypeAbstractViewHolder) holder).bindHolder(mOneList.get(realPosition));                break;            case DataModel.TYPE_TWO:
                ((TypeAbstractViewHolder) holder).bindHolder(mTwoList.get(realPosition));                break;            case DataModel.TYPE_THREE:
                ((TypeAbstractViewHolder) holder).bindHolder(mThreeList.get(realPosition));                break;
        }
    }    @Override
    public int getItemCount() {        return mTypes.size();
    }    @Override
    public int getItemViewType(int position) {        return mTypes.get(position);
    }
}

到此,RecyclerView实现复杂布局结束了,还是希望大家有时间多看多敲,多去理解。

GitHub地址

https://github.com/HLQ-Struggle/MaterialDesignStudy

学习地址

> 泥阿布慕课网视频地址:http://www.imooc.com/learn/731

> 废大半天劲儿找到的GitHub地址:https://github.com/nimengbo

> 图片地址:http://www.jianshu.com/p/29465cce1131

结束

我们沿着前人的路慢慢前行,只要坚持,就会有收获,可能目前的现状有些不尽人意,但是只要坚持下去,希望的曙光始终会照亮前行的路~

致自己,致坚持看完本文的你~加油~

原文链接:http://www.apkbus.com/blog-904057-75990.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP