关于NewHomeFragment商城首页编写

商城首页App的编写,首先我们要确定我们需要确定一下大框架:


无标题绘图.jpg

如图所示,我们可以看到,首先我们需要一个内容根布局,和一个标题栏,之后是RecyclerView,之所以使用RecyclerView,是因为我们通过联网访问需要获取到实时数据。可以根据内容自定义我们需要的View,然后添加到RecyclerView中,有多少就能写多了.不用担心数据会储存不下去。好了,基本框架说完了,让我们来看看如何实现。
首先是关于ToolBar的标题栏和状态栏,因为手机本身显示内容界面有限,所以,为了保证用户能够流畅的去使用我们的app,就需要对标题栏和状态栏进行改动。
一.沉浸式状态栏:
何为沉浸式状态栏,有人可能说,像饿了吗,美团,qq那种状态栏和背景色一致,就是沉浸式状态栏,其实不然,这里参考郭霖大神的博客https://blog.csdn.net/guolin_blog/article/details/51763825
何为沉浸式,就是像游戏,电影,电视剧那样给人带来观赏体验,让人沉浸其中,不受系统UI的影响,比如像下图:

TIM截图20181004105128.png

像这样,用户不会被标题栏与状态栏所干扰,称为沉浸式状态栏。
其他的App则是被称作透明状态栏这里我简单介绍下透明状态栏如何实现
首先现将状态栏和标题栏隐藏:

 View decorView = getWindow().getDecorView();
 int option = View.SYSTEM_UI_FLAG_FULLSCREEN; 
 decorView.setSystemUiVisibility(option);
 ActionBar actionBar = getSupportActionBar();
 actionBar.hide();

效果如下:


941206-20161008131410848-553960216.png

当然,这也不是沉浸式的,只是隐藏了标题栏和状态栏,应该算是全屏模式吧,引导页就可以这么制作。下面我们修改下代码:

if (Build.VERSION.SDK_INT >= 21) {
    View decorView = getWindow().getDecorView();
    int option = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
    decorView.setSystemUiVisibility(option);
    getWindow().setNavigationBarColor(Color.TRANSPARENT);
    getWindow().setStatusBarColor(Color.TRANSPARENT);
}
ActionBar actionBar = getSupportActionBar();
actionBar.hide();

透明状态栏只有在5.0的时候才会有效果,所以我们需要对这里进行SDK的判断。接下来我们使用了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_STABLE,注意两个Flag必须要结合在一起使用,表示会让应用的主体内容占用系统状态栏的空间,最后再调用Window的setStatusBarColor()方法将状态栏设置成透明色就可以了。效果如下:


941206-20161008131302176-1520150565.png

好了,完成透明状态栏以后,我们开始编写布局代码:


<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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="match_parent">

    <android.support.v4.widget.SwipeRefreshLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <android.support.v7.widget.Toolbar
                android:id="@+id/tool_bar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@color/colorYelloFFDE00" />

            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv_fragment_home_context"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_below="@+id/tool_bar"
                android:background="@color/color_rv_bg"
                android:clipToPadding="true"
                android:descendantFocusability="blocksDescendants"
                android:paddingLeft="0dp"
                android:paddingRight="0dp"
                android:requiresFadingEdge="none"
                android:scrollbars="none" />
        </RelativeLayout>
    </android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>

布局还是很简单的,这里不再赘述了,我们所需要的就是从网络获取到json数据,然后再讲json转化为我们需要的信息展示到用户UI界面上
所以我们需要对RecyclerView进行定制。这里介绍阿里的开源框架VirtualLayout
VirtualLayout是什么:
VirtualLayout是一个针对RecyclerView的LayoutManager扩展, 主要提供一整套布局方案和布局间的组件复用的问题。
VirtualLayout有什么作用
通过定制化的LayoutManager,接管整个RecyclerView的布局逻辑;LayoutManager管理了一系列LayoutHelper,LayoutHelper负责具体布局逻辑实现的地方;每一个LayoutHelper负责页面某一个范围内的组件布局;不同的LayoutHelper可以做不同的布局逻辑,因此可以在一个RecyclerView页面里提供异构的布局结构,这就能比系统自带的LinearLayoutManager、GridLayoutManager等提供更加丰富的能力。同时支持扩展LayoutHelper来提供更多的布局能力。默认通用布局实现,解耦所有的View和布局之间的关系: Linear, Grid, 吸顶, 浮动, 固定位置等。

① LinearLayoutHelper: 线性布局

②GridLayoutHelper: Grid布局, 支持横向的colspan

③FixLayoutHelper: 固定布局,始终在屏幕固定位置显示

④ScrollFixLayoutHelper: 固定布局,但之后当页面滑动到该图片区域才 显示, 可以用来做返回顶部或其他书签等

⑤FloatLayoutHelper:浮动布局,可以固定显示在屏幕上,但用户可以拖拽其位置

⑥ColumnLayoutHelper: 栏格布局,都布局在一排,可以配置不同列之间的宽度比值

⑦SingleLayoutHelper: 通栏布局,只会显示一个组件View

⑧OnePlusNLayoutHelper: 一拖N布局,可以配置1-5个子元素

⑨StickyLayoutHelper: stikcy布局, 可以配置吸顶或者吸底

⑩StaggeredGridLayoutHelper:瀑布流布局,可配置间隔高度/宽度

上述默认实现里可以大致分为两类:一是非fix类型布局,像线性、Grid、栏格等,它们的特点是布局在整个页面流里,随页面滚动而滚动;另一类就是fix类型的布局,它们的子节点往往不随页面滚动而滚动。

所有除布局外的组件复用,VirtualLayout将用来管理大的模块布局组合,扩展了RecyclerView,使得同一RecyclerView内的组件可以复用,减少View的创建和销毁过程。

VirtualLayout的使用
① 初始化LayoutManger

        mlayoutManager = new VirtualLayoutManager(getActivity());
        mRecyclerView.setLayoutManager(mlayoutManager);

②设置回收复用池大小,(如果一屏内相同类型的 View 个数比较多,需要设置一个合适的大小,防止来回滚动时重新创建 View):

        mviewPool = new RecyclerView.RecycledViewPool();
        mRecyclerView.setRecycledViewPool(mviewPool);
        mviewPool.setMaxRecycledViews(0, 20);

这里,因为界面样式比较多,所以,我们自定义Adapter去继承DelegateAdapter.adapter,按照需求去编写我们的界面

public class GeneralVLayoutAdapter extends DelegateAdapter.Adapter<GeneralVLayoutAdapter.MainViewHolder> {
    private Context mContext;
    private LayoutHelper helper;
    private VirtualLayoutManager.LayoutParams params;
    private int mCount = 0;

    public GeneralVLayoutAdapter(Context context, LayoutHelper helper,
                                 VirtualLayoutManager.LayoutParams params, int count) {
        mContext = context;
        this.helper = helper;
        this.params = params;
        mCount = count;
    }

    public GeneralVLayoutAdapter(Context context, LayoutHelper helper, int count) {
        this(context, helper, null, count);
    }

    @Override
    public LayoutHelper onCreateLayoutHelper() {
        return helper;
    }

    @NonNull
    @Override
    public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, int i) {
        if (params != null) {
            mainViewHolder.itemView.setLayoutParams(new VirtualLayoutManager.LayoutParams(params));
        }
    }

    @Override
    public int getItemCount() {
        return mCount;
    }

    public class MainViewHolder extends RecyclerView.ViewHolder {
        public MainViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
}

这段代码也很简单我们需要关注一下几个方法

  • onCreateViewHolder 这个方法需要我们去重写,因为每个布局对应的viewHolder都不一样,所以需要我们在不同的布局里去重写对应的ViewHolder。

  • onBindViewHolder 这个方法也需要我们去重写,对应着ViewHolder的子项的数据进行赋值,

  • getItemCount 这个方法更简单了,它相当于告诉了RecyclerView有多少个子项,直接返回数据源的长度。因为RecyclerView已经为我们封装好了ViewHolder,所以我们的MainViewHolder直接继承RecyclerView的ViewHolder,这没啥好说的。

    private DelegateAdapter mdelegateAdapter;
    private List<DelegateAdapter.Adapter> madapters = new LinkedList<>();
    mdelegateAdapter = new DelegateAdapter(mlayoutManager, false);
    mRecyclerView.setAdapter(mdelegateAdapter);

这里的代码需要我们综合去看,因为一个布局就对应着一个adapter,所以我们需要一个集合去添加这些adapter.下面会在代码展示,就不详细说明了。
接下来我们要准备工具,将获取到的json数据转化为UI界面,我们需要使用到OkHttp
相信很多人都使用过,因为比google推送的HttpURLConnection连接要快捷简便的多。使用方法如下,首先我们需要添加库依赖,编辑Gradle文件

implementation 'com.squareup.okhttp3:okhttp:3.11.0'

同时也要添加权限编辑manifest文件

<uses-permission android:name="android.permission.INTERNET" />

这样我们就能访问网络,获取JSON数据了

public class OkHttpUtil {
    private static OkHttpUtil okHttpUtil = null;
    private OkHttpClient mHttpClient;
    private Request mRequest;

    public OkHttpUtil() {

    }

    public static OkHttpUtil getInstance() {
        if (okHttpUtil == null) {
            synchronized (OkHttpUtil.class) {
                if (okHttpUtil == null) {
                    okHttpUtil = new OkHttpUtil();
                }
            }
        }
        return okHttpUtil;
    }

    public void startGet(String url, final OnNetResultListener listener) {
        mHttpClient = new OkHttpClient();
        mRequest = new Request.Builder().url(url).build();
        mHttpClient.newCall(mRequest).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                listener.OnFailureListener(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                listener.OnSuccessListener(response.body().string());
            }
        });
    }

    public void startPost(String url, String phone, String username, String password, String data,
                          final OnNetResultListener listener) {
        mHttpClient = new OkHttpClient();
        final RequestBody requestBody = new FormBody.Builder()
                .add("phone", phone)
                .add("username", username)
                .add("password", password)
                .add("regdate", data)
                .build();

        mRequest = new Request.Builder().url(url).post(requestBody).build();
        mHttpClient.newCall(mRequest).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                listener.OnFailureListener(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                listener.OnSuccessListener(response.body().string());
            }
        });
    }

}

这是一个封装好的工具类,思路也很简单,首先我们需要一个okHttpClient的实例,因为我们需要访问网络,所以我们也需要访问URL地址,如果要访问,自然就需要Request对象,需要注意的是我们的访问请求是GET还是Post,其实GET和Post差不多,稍微复杂点,Post需要构建出一个RequestBody对象,来存储我们需要提交的参数,然后用post的方法将参数提交,接下来,就是和Get一样的操作。,好了,这样我们就成功的发送了请求。如果请求成功,我们会得到数据源,这个时候我们就需要对其解析,传送数据分为XML和JSON两种格式,这里我们主要说下如何对JSON数据的解析,XML暂且不做考虑,主要说一下如何解析JSON数据

public class JsonUtil {
    private static final int HOME_COODS_INFO = 0;
    private static final int BANK_CARD_INFO = 1;
    private static final int CLASSIFY_GOODS_INFO = 2;
    private static final int MALL_GOODS_INFO = 3;
    private static final int GOODS_DETAILS_INFO = 4;

    public List getDataFromJson(String json, int type) {
        List<HomeSortInfo> homeSortInfos = new ArrayList<>();
        List<HomeSortItemfo> homeSortItemfos = new ArrayList<>();
        JSONObject mJsonObject;
        JSONArray mJsonArray;
        try {
            if (type == HOME_COODS_INFO) {
                //首页的商品信息
                mJsonObject = new JSONObject(json);
                mJsonArray = mJsonObject.getJSONArray("home_sort");
                for (int i = 0; i < mJsonArray.length(); i++) {
                    JSONObject jsonObject = (JSONObject) mJsonArray.get(i);
                    String title = jsonObject.getString("title");
                    String sortImageUrl = jsonObject.getString("sortImageUrl");
                    JSONArray jsonArray = jsonObject.getJSONArray("goods");
                    for (int j = 0; j < jsonArray.length(); j++) {
                        JSONObject jsonObject1 = (JSONObject) jsonArray.get(j);
                        String id = jsonObject1.getString("id");
                        String goodsImageUrl = jsonObject1.getString("goodsImageUrl");
                        homeSortItemfos.add(new HomeSortItemfo(id, goodsImageUrl));
                    }
                    homeSortInfos.add(new HomeSortInfo(title, sortImageUrl, homeSortItemfos));
                }
                LogUtil.d("LF1234", "homeSortInfos" + homeSortInfos);
                return homeSortInfos;
            } else if (type == BANK_CARD_INFO) {


            } else if (type == CLASSIFY_GOODS_INFO) {
                List<ClassifyGoodsInfo> classifyGoodsInfos = new ArrayList<>();
                mJsonObject = new JSONObject(json);
                mJsonArray = mJsonObject.getJSONArray("classifyTitle");
                for (int i = 0; i < mJsonArray.length(); i++) {
                    JSONObject jsonObject = (JSONObject) mJsonArray.get(i);
                    String title = jsonObject.getString("title");
                    String headerImageUrl = jsonObject.getString("headerImageUrl");
                    String subtitle1 = jsonObject.getString("subTitle1");
                    String subtitle2 = jsonObject.getString("suTitle");
                    JSONArray jsonArray = ((JSONObject) mJsonArray.get(i)).getJSONArray("gridImageUrls1");

                    List<ClassifyGridInfo> mGridInfos1 = new ArrayList<>();
                    List<ClassifyGridInfo> mGridInfos2 = new ArrayList<>();

                    for (int j = 0; j < jsonArray.length(); j++) {
                        JSONObject jsonObject1 = (JSONObject) jsonArray.get(j);
                        int id = jsonObject1.getInt("id");
                        String desc = jsonObject1.getString("desc");
                        String imageUrl = jsonObject1.getString("iamgeUrl");
                        mGridInfos1.add(new ClassifyGridInfo(id, desc, imageUrl));
                    }
                    JSONArray jsonArray1 = ((JSONObject) mJsonArray.get(i)).getJSONArray("gridImageUrls2");
                    for (int j = 0; j < jsonArray1.length(); j++) {
                        JSONObject jsonObject1 = (JSONObject) jsonArray1.get(j);
                        int id = jsonObject1.getInt("id");
                        String desc = jsonObject1.getString("desc");
                        String imageUrl = jsonObject1.getString("iamgeUrl");
                        mGridInfos2.add(new ClassifyGridInfo(id, desc, imageUrl));
                    }
                    classifyGoodsInfos.add(new ClassifyGoodsInfo(title, headerImageUrl, subtitle1, subtitle2, mGridInfos1, mGridInfos2));
                }
                return classifyGoodsInfos;
            } else if (type == MALL_GOODS_INFO) {
                List<MallPagerInfo> mallPagerInfos = new ArrayList<>();
                List<BannerInfo> bannerInfos = new ArrayList<>();
                List<GridInfo> gridInfos = new ArrayList<>();
                List<BannerInfo> goodsInfos = new ArrayList<>();
                List<MallGoodsInfo> mallGoodsInfos = new ArrayList<>();
                mJsonObject = new JSONObject(json);

                String singleImageUrl = mJsonObject.getString("single_image");
                mJsonArray = mJsonObject.getJSONArray("banners");
                for (int i = 0; i < mJsonArray.length(); i++) {
                    JSONObject jsonObject = (JSONObject) mJsonArray.get(i);
                    bannerInfos.add(new BannerInfo(jsonObject.getString("banner_url")));
                }
                JSONArray jsonArrayGrid = mJsonObject.getJSONArray("classifyGridItems");
                for (int i = 0; i < jsonArrayGrid.length(); i++) {
                    JSONObject jsonObject = (JSONObject) jsonArrayGrid.get(i);
                    gridInfos.add(new GridInfo(
                            jsonObject.getString("desc"),
                            jsonObject.getString("grid_url")));
                }

                JSONArray jsonArrayGoods = mJsonObject.getJSONArray("four_goods_image");
                for (int i = 0; i < jsonArrayGoods.length(); i++) {
                    JSONObject jsonObject = (JSONObject) jsonArrayGoods.get(i);
                    goodsInfos.add(new BannerInfo(jsonObject.getString("four_image_url")));
                }
                JSONArray jsonArrayHotSorts = mJsonObject.getJSONArray("hotSort");
                for (int i = 0; i < jsonArrayHotSorts.length(); i++) {
                    List<MallGoodsItemInfo> mallGoodsItemInfos = new ArrayList<>();
                    JSONObject jsonObject = (JSONObject) jsonArrayHotSorts.get(i);
                    String headerImageUrl = jsonObject.getString("headerBigImage");
                    JSONArray jsonArray = jsonObject.getJSONArray("threeGoods");
                    for (int j = 0; j < jsonArray.length(); j++) {
                        JSONObject jsonObject1 = (JSONObject) jsonArray.get(j);
                        mallGoodsItemInfos.add(new MallGoodsItemInfo(
                                jsonObject1.getString("goodsItemImage"),
                                jsonObject1.getString("desc"),
                                jsonObject1.getDouble("singePrice"),
                                jsonObject1.getInt("numPeriods"),
                                jsonObject1.getDouble("price")));
                    }
                    mallGoodsInfos.add(new MallGoodsInfo(headerImageUrl, mallGoodsItemInfos));
                }
                JSONArray jsonArrayReco = mJsonObject.getJSONArray("recommends_goods");
                List<RecommendGoodsInfo> recommendGoodsInfoList = new ArrayList<>();
                for (int i = 0; i < jsonArrayReco.length(); i++) {
                    JSONObject jsonObject = (JSONObject) jsonArrayReco.get(i);
                    recommendGoodsInfoList.add(new RecommendGoodsInfo(
                            jsonObject.getString("imageUrl"),
                            jsonObject.getString("desc"),
                            jsonObject.getDouble("singlePrice"),
                            jsonObject.getInt("periods"),
                            jsonObject.getDouble("totalPrice"),
                            jsonObject.getString("rate")));
                }
                mallPagerInfos.add(new MallPagerInfo(
                        bannerInfos,
                        gridInfos,
                        singleImageUrl,
                        goodsInfos,
                        mallGoodsInfos,
                        recommendGoodsInfoList));
                return mallPagerInfos;
            } else if (type == GOODS_DETAILS_INFO) {

            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return null;
    }

}

这是我自己的解析工具类使用的是JSONObject解析,很简单,我们首先创建数据模型bean,比如说,姓名,年龄,性别,可能都是在同一段节点的同一数据源中,所以我们用bean的模式,然后创建各属性的get和set方法。再用list集合去添加,然后在遍历集合的形式,将解析的数据展示到我们的界面上。下面贴出bean的代码

public class ClassifyGridInfo {
    private int id;
    private String name;
    private String imageUrl;

    public ClassifyGridInfo(int id, String name, String imageUrl) {
        this.id = id;
        this.name = name;
        this.imageUrl = imageUrl;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }
}

再贴出JSON数据源

[{"id":"1","name":"**","imageUrl":"****"},{"id":"2","name":"**","imageUrl":"****"},
{"id":"1","name":"**","imageUrl":"****"},.....
]

这里只是举例,我们通过JSONArray将数据源转化成JSONObject,然后通过JSONObject去获取每一个元素的属性值,这里就不在赘述了。
好了,有了这些工具,下面我们来说一下关于展示界面的UI设计。
一、轮播图
轮播图是一种很常见的动态UI界面,如下图所示:

1-NTfaUB2N8OSxAGnJig333w.jpeg

这是网站上的轮播图,用户对于轮播图的反映褒贬不一,但是不可否认,它能够很直观的给用户以需求,介绍自己产品的特色,如何实现轮播图,将是我们的重点,我会使用RecyclerView去实现轮播效果。
首先,我们需要的是自定义控件属性,对,你没有听错,是自定义控件属性,因为有时候控件属性不能满足我们的需求,所以,我们需要自定义控件属性,首先,我们需要在res文件夹下values文件下新建一个attrs文件夹,用于存放我们自定义控件的属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RecyclerViewBanner">
        <attr name="rvb_interval" format="integer" />
        <attr name="rvb_showIndicator" format="boolean" />
        <attr name="rvb_indicatorSelectedSrc" format="color|reference" />
        <attr name="rvb_indicatorUnSelectedSrc" format="color|reference" />
        <attr name="rvb_indicatorSize" format="dimension|reference" />
        <attr name="rvb_indicatorSpace" format="dimension|reference" />
        <attr name="rvb_indicatorMargin" format="dimension|reference" />
        <attr name="rvb_indicatorGravity" format="enum">
            <enum name="left" value="0" />
            <enum name="center" value="1" />
            <enum name="right" value="2" />
        </attr>
        <attr name="rvb_autoPlaying" format="boolean" />
    </declare-styleable>

下面我们来一个个分析一下

  • <declare-styleable name=“”/> 这是一个资源文件的索引名,类似Id,在代码编写时候,能够很快确定你的自定义控件属性位置。
  • <attr name= "" format = " "/>attr name 是申明你想自定义控件的属性的名称 format 则是设定控件属性类型
    color:颜色值。boolean:布尔值。dimension:尺寸值。float:浮点值。integer:整型值。string:字符串。fraction:百分数。enum:枚举值。flag:位或运算。reference:参考某一资源ID。
    现在我们新建一个类去继承FragmentLayout;
public class RecyclerViewBanner extends FrameLayout {
    private static final int DEFAULT_SELECT_COLOR = 0xffffffff;//选中时的颜色
    private static final int DEFAULT_UNSELECTED_COLOR = 0X50ffffff;//未来选中时的颜色
    private RecyclerView mRecyclerView;
    private RecyclerViewAdapter adapter;
    private LinearLayout mLinearLayout;
    private OnRvBannerClickListener listener;
    private OnSwitchRvBannerListener onSwitchRvBannerListener;
    private boolean isPlaying;//是否播放
    private int startX, startY, currentIndex;//从X轴开始的位置,从Y轴开始的位置
    private int mSize;//大小
    private int mSpace;//间距
    private int mInterval;//时间间隔
    private int margin;//距离外边距的距离
    private int gravity;//位置
    private boolean isShowIndicator;//是否显示指示器
    private boolean isAutoPlaying;//是否自动播放
    private boolean isTouched;//是否触摸
    private List<Object> mData = new ArrayList<>();
    private Drawable mSelectedDrawable;//选中时背景
    private Drawable mUnSelectedDrawable;//未选中时的背景
    private Drawable selectedSrc;//选中时的资源
    private Drawable unSelectedSrc;//未选中时的资源
    private Handler mHandler = new Handler();
    private Runnable playTask = new Runnable() {
        @Override
    public void run() {
            mRecyclerView.smoothScrollToPosition(++currentIndex);//让RecyclerView平滑到指定的位置
            if (isShowIndicator) {
                changePoint();//改变圆点指示器的显示位置
            }
            mHandler.postDelayed(this, mInterval);//设置定时器
        }
    };
    public RecyclerViewBanner(@NonNull Context context) {
        super(context);
        init(context, null);
    }

    public RecyclerViewBanner(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public RecyclerViewBanner(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }
}
    private void init(final Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecyclerViewBanner);
        mInterval = typedArray.getInt(R.styleable.RecyclerViewBanner_rvb_interval, 3000);
        isShowIndicator = typedArray.getBoolean(R.styleable.RecyclerViewBanner_rvb_showIndicator,
                true);
        isAutoPlaying = typedArray.getBoolean(R.styleable.RecyclerViewBanner_rvb_autoPlaying,
                true);
        selectedSrc = typedArray.getDrawable(R.styleable.RecyclerViewBanner_rvb_indicatorSelectedSrc);
        unSelectedSrc = typedArray.getDrawable(R.styleable.RecyclerViewBanner_rvb_indicatorUnSelectedSrc);
        mSize = typedArray.getDimensionPixelSize(R.styleable.RecyclerViewBanner_rvb_indicatorSize,
                0);
        mSpace = typedArray.getDimensionPixelSize(R.styleable.RecyclerViewBanner_rvb_indicatorSpace,
                dp2px(4));

        margin = typedArray.getDimensionPixelSize(R.styleable.RecyclerViewBanner_rvb_indicatorMargin,
                dp2px(10));
        int g = typedArray.getInt(R.styleable.RecyclerViewBanner_rvb_indicatorGravity,
                1);
        switch (g) {
            case 0:
                gravity = Gravity.START;
                break;
            case 1:
                gravity = Gravity.CENTER;
                break;
            case 2:
                gravity = Gravity.END;
                break;
            default:
                break;
        }
        if (selectedSrc == null) {
            mSelectedDrawable = gradientDrawable(DEFAULT_SELECT_COLOR);
        } else {
            if (selectedSrc instanceof ColorDrawable) {
                mSelectedDrawable = gradientDrawable(((ColorDrawable) selectedSrc).getColor());
            } else {
                mSelectedDrawable = selectedSrc;
            }
        }

        if (unSelectedSrc == null) {
            mUnSelectedDrawable = gradientDrawable(DEFAULT_UNSELECTED_COLOR);
        } else {
            if (unSelectedSrc instanceof ColorDrawable) {
                mUnSelectedDrawable = gradientDrawable(((ColorDrawable) unSelectedSrc).getColor());
            } else {
                mUnSelectedDrawable = unSelectedSrc;
            }
        }
        typedArray.recycle();//回收 TypedArray,用于后续调用时可复用之。当调用该方法后,不能再操作该变量。

        mRecyclerView = new RecyclerView(context);
        mLinearLayout = new LinearLayout(context);
        new PagerSnapHelper().attachToRecyclerView(mRecyclerView);//辅助Recycler进行滚动对齐
        adapter = new RecyclerViewAdapter();
        mRecyclerView.setAdapter(adapter);
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    int first = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
                    int last = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition();
                    if (currentIndex != (first + last) / 2) {
                        currentIndex = (first + last) / 2;
                        changePoint();
                    }
                }
            }
        });
        mLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
        mLinearLayout.setGravity(Gravity.CENTER);
        LayoutParams vpLayoutParams = new LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

        LayoutParams linearLayoutParams = new LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        linearLayoutParams.gravity = Gravity.BOTTOM | gravity;
        linearLayoutParams.setMargins(margin, margin, margin, margin);

        addView(mRecyclerView, vpLayoutParams);
        addView(mLinearLayout, linearLayoutParams);
    }
/**
     * 设置间隔时间
     *
     * @param mInterval
     */
    public void setmInterval(int mInterval) {
        this.mInterval = mInterval;
    }

    /**
     * 设置是否指示器导航点
     *
     * @param showIndicator
     */
    public void setShowIndicator(boolean showIndicator) {
        isShowIndicator = showIndicator;
    }

    /**
     * 设置是否禁止滚动播放
     *
     * @param autoPlaying
     */
    public void setAutoPlaying(boolean autoPlaying) {
        isAutoPlaying = autoPlaying;
    }

    /**
     * 设置是否自动播放(上锁)
     *
     * @param playing 开始播放
     */
    private synchronized void setPlaying(boolean playing) {
        if (isAutoPlaying) {
            if (!isPlaying && playing && adapter != null && adapter.getItemCount() > 2) {
                mHandler.postDelayed(playTask, mInterval);
                isPlaying = true;
            } else if (isPlaying && !playing) {
                mHandler.removeCallbacksAndMessages(null);
                isPlaying = false;
            }
        }
    }

    //手指触摸事件
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = (int) ev.getX();
                startY = (int) ev.getY();
                //阻止父层View拦截事件
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) ev.getX();
                int moveY = (int) ev.getY();
                int disX = moveX - startX;
                int disY = moveY - startY;
                boolean hasMoved = 2 * Math.abs(disX) > Math.abs(disY);
                getParent().requestDisallowInterceptTouchEvent(hasMoved);
                if (hasMoved) {
                    setPlaying(false);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_CANCEL:
                if (!isPlaying) {
                    isTouched = true;
                    setPlaying(true);
                }
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        setPlaying(true);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        setPlaying(false);
    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        if (visibility == GONE || visibility == INVISIBLE) {
            // 停止轮播
            setPlaying(false);
        } else if (visibility == VISIBLE) {
            // 开始轮播
            setPlaying(true);
        }
        super.onVisibilityChanged(changedView, visibility);
    }

    //创建默认指示器
    private GradientDrawable gradientDrawable(int color) {
        GradientDrawable gradientDrawable = new GradientDrawable();
        gradientDrawable.setSize(dp2px(6), dp2px(6));
        gradientDrawable.setCornerRadius(dp2px(6));
        gradientDrawable.setColor(color);
        return gradientDrawable;
    }


    /**
     * 指示器整体由数据列表容量数量的AppCompatImageView均匀分布在一个横向的LinearLayout中构成
     * 使用AppCompatImageView的好处是在Fragment中也使用Compat相关属性
     */
    private void createIndicators() {
        mLinearLayout.removeAllViews();//先动态移除所有的View
        for (int i = 0; i < mData.size(); i++) {
            ImageView imageView = new ImageView(getContext());
            LinearLayout.LayoutParams indicatorsParams = new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            indicatorsParams.leftMargin = mSpace / 2;
            indicatorsParams.rightMargin = mSpace / 2;
            if (mSize >= dp2px(4)) {
                indicatorsParams.width = indicatorsParams.height = mSize;
            } else {
                imageView.setMinimumHeight(dp2px(2));
                imageView.setMinimumWidth(dp2px(2));
            }
            imageView.setImageDrawable(i == 0 ? mSelectedDrawable : mUnSelectedDrawable);
            mLinearLayout.addView(imageView, indicatorsParams);
        }
    }

    //将int值转化为dp值
    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
    }


    /**
     * 设置轮播数据
     *
     * @param data
     */
    public void setRvBannerData(List data) {
        setPlaying(false);
        mData.clear();
        if (null != data) {
            mData.addAll(data);
        }
        if (mData.size() > 1) {
            currentIndex = mData.size();
            adapter.notifyDataSetChanged();
            mRecyclerView.scrollToPosition(currentIndex);
            if (isShowIndicator) {
                createIndicators();
            }
            setPlaying(true);
        } else {
            currentIndex = 0;
            adapter.notifyDataSetChanged();
        }

    }

    private void changePoint() {
        if (mLinearLayout != null && mLinearLayout.getChildCount() > 0) {
            for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
                ((ImageView) mLinearLayout.getChildAt(i)).setImageDrawable(
                        i == currentIndex % mData.size() ? mSelectedDrawable : mUnSelectedDrawable);
            }
        }
    }

    class RecyclerViewAdapter extends RecyclerView.Adapter {

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
            SimpleDraweeView simpleDraweeView = new SimpleDraweeView(viewGroup.getContext());
            RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            simpleDraweeView.setLayoutParams(layoutParams);
            simpleDraweeView.setId(R.id.rvb_banner_imageView_id);
            simpleDraweeView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            simpleDraweeView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (listener != null) {
                        listener.OnClick(currentIndex % mData.size());
                    }
                }
            });

            return new RecyclerView.ViewHolder(simpleDraweeView) {
            };
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
            SimpleDraweeView draweeView = viewHolder.itemView.findViewById(R.id.rvb_banner_imageView_id);
            if (onSwitchRvBannerListener != null) {
                onSwitchRvBannerListener.switchBanner(i % mData.size(), draweeView);
            }

        }

        @Override
        public int getItemCount() {
            return mData == null ? 0 : mData.size() < 2 ? mData.size() : Integer.MAX_VALUE;
        }
    }

    public void setListener(OnRvBannerClickListener listener) {
        this.listener = listener;
    }

    public void setOnSwitchRvBannerListener(OnSwitchRvBannerListener onSwitchRvBannerListener) {
        this.onSwitchRvBannerListener = onSwitchRvBannerListener;
    }


    private class PagerSnapHelper extends LinearSnapHelper {

        @Override
        public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
            //获取到将要滚动的位置targetPos
            int targetPos = super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
            //找到与之最近的view
            View currentView = findSnapView(layoutManager);
            if (targetPos != RecyclerView.NOT_FOCUSABLE && null != currentView) {
                //获取最近View的位置currentPos
                int currentPos = layoutManager.getPosition(currentView);
                int first = ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
                int last = ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
                //如果滑动的位置<最近view的位置,最近的view的位置对齐最后一个可见view的位置
                //如果滑动的位置>最近view的位置,最近的view的位置对齐第一个可见的View的位置
                currentPos = targetPos < currentPos ? last : (targetPos > currentPos ? first : currentPos);
                //如果滑动的位置<最后一个可见view的位置,将要滑动的位置对齐第一个view
                //如果滑动的位置>第一个可见view的位置,将要滑动的位置对齐最后一个view
                targetPos = targetPos < currentPos ? currentPos - 1 : (
                        targetPos > currentPos ? currentPos + 1 : currentPos);
            }
            return targetPos;
        }
    }

我们继承FrameLayout需要重写他的三个构造方法

  • public RecyclerViewBanner(@NonNull Context context) {
    super(context);
    init(context, null);
    }
  • public RecyclerViewBanner(@NonNull Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
    }
  • public RecyclerViewBanner(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs);
    }

    一般来说,前两个构造函数就足够,第三个构造函数的第三个参数是用来设置默认的style样式,目前不考虑,传入参数为0即可。我们需要注意的是AttributeSet attrs这个参数,它就是需要我们传入的自定义控件属性的参数。我们通过TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecyclerViewBanner);获取到当前自定义控件属性集合,然后对应编写默认属性。轮播图肯定是图片加指示器,有多少图片,就应该对应多少个指示器,首先我们先编写RecyclerView容器。
        mRecyclerView = new RecyclerView(context);
        mLinearLayout = new LinearLayout(context);
        new PagerSnapHelper().attachToRecyclerView(mRecyclerView);//辅助Recycler进行滚动对齐
        adapter = new RecyclerViewAdapter();
        mRecyclerView.setAdapter(adapter);
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    int first = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
                    int last = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition();
                    if (currentIndex != (first + last) / 2) {
                        currentIndex = (first + last) / 2;
                        changePoint();
                    }
                }
            }
        });
        mLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
        mLinearLayout.setGravity(Gravity.CENTER);
        LayoutParams vpLayoutParams = new LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

        LayoutParams linearLayoutParams = new LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        linearLayoutParams.gravity = Gravity.BOTTOM | gravity;
        linearLayoutParams.setMargins(margin, margin, margin, margin);

        addView(mRecyclerView, vpLayoutParams);
        addView(mLinearLayout, linearLayoutParams);

这段代码我们要重点是new PagerSnapHelper().attachToRecyclerView(mRecyclerView);//辅助Recycler进行滚动对齐和对RecyclerView的滚动监听,第一个方法是通过对滑动速度定位图片位置这里推荐大家去看这篇简书https://www.jianshu.com/p/e54db232df62
第二个方法是防止RecyclerView停止滑动后,图片位置产生偏差,用于修正。接下来就需要编写adapter,这个相信大家已经非常熟练了。

class RecyclerViewAdapter extends RecyclerView.Adapter {

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
            SimpleDraweeView simpleDraweeView = new SimpleDraweeView(viewGroup.getContext());
            RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            simpleDraweeView.setLayoutParams(layoutParams);
            simpleDraweeView.setId(R.id.rvb_banner_imageView_id);
            simpleDraweeView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            simpleDraweeView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (listener != null) {
                        listener.OnClick(currentIndex % mData.size());
                    }
                }
            });

            return new RecyclerView.ViewHolder(simpleDraweeView) {
            };
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
            SimpleDraweeView draweeView = viewHolder.itemView.findViewById(R.id.rvb_banner_imageView_id);
            if (onSwitchRvBannerListener != null) {
                onSwitchRvBannerListener.switchBanner(i % mData.size(), draweeView);
            }

        }

        @Override
        public int getItemCount() {
            return mData == null ? 0 : mData.size() < 2 ? mData.size() : Integer.MAX_VALUE;
        }
    }

这段代码也没有啥难点,直接使用了simpleDraweeView去填充RecyclerView布局就行了。
有人问了,如何实现轮播,这个还是很简单的,只需要利用handler定时异步操作就行了,我们还需要注意的一个地方是对于触摸的监听

 //手指触摸事件
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = (int) ev.getX();
                startY = (int) ev.getY();
                //阻止父层View拦截事件
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) ev.getX();
                int moveY = (int) ev.getY();
                int disX = moveX - startX;
                int disY = moveY - startY;
                boolean hasMoved = 2 * Math.abs(disX) > Math.abs(disY);
                getParent().requestDisallowInterceptTouchEvent(hasMoved);
                if (hasMoved) {
                    setPlaying(false);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_CANCEL:
                if (!isPlaying) {
                    isTouched = true;
                    setPlaying(true);
                }
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

对应的触摸事件是按下:ACTION_DOWN,滑动:ACTION_MOVE,抬起:ACTION_UP,结束:ACTION_CANCEL,根据这些触摸事件,判定轮播图是否停止或开始自动轮播。
这样,我们的轮播图就编写完成了。我们去Fragment添加一下吧

        SingleLayoutHelper singleLayoutHelper = new SingleLayoutHelper();
        GeneralVLayoutAdapter bannerAdapter = new GeneralVLayoutAdapter(
                getContext(), singleLayoutHelper, 1) {
            @NonNull
            @Override
            public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
                View view = LayoutInflater.from(getContext()).inflate(
                        R.layout.home_pager_bannner_layout, viewGroup, false);
                return new MainViewHolder(view);
            }

            @Override
            public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, int i) {
                super.onBindViewHolder(mainViewHolder, i);
                mRecyclerViewBanner = mainViewHolder.itemView.findViewById(R.id.rvb_home_banner);
                mBannerInfos = new ArrayList<>();
                mBannerInfos.add(new BannerInfo("https://i.loli.net/2018/04/06/5ac733bc51d0a.png"));
                mBannerInfos.add(new BannerInfo("https://i.loli.net/2018/04/06/5ac735502effe.png"));
                mBannerInfos.add(new BannerInfo("https://i.loli.net/2018/04/07/5ac8459fc9b6a.png"));
                mBannerInfos.add(new BannerInfo("https://i.loli.net/2018/04/06/5ac7339ee876e.jpg"));
                mRecyclerViewBanner.setRvBannerData(mBannerInfos);
                mRecyclerViewBanner.setOnSwitchRvBannerListener(new OnSwitchRvBannerListener() {
                    @Override
                    public void switchBanner(int position, SimpleDraweeView draweeView) {
                        draweeView.setImageURI(mBannerInfos.get(position).getUrl());
                    }
                });
                mRecyclerViewBanner.setListener(new OnRvBannerClickListener() {
                    @Override
                    public void OnClick(int position) {
                        toWebActivity(UrlInfoBean.homeBannerUrls[position]);
                    }
                });
            }
        };
        madapters.add(bannerAdapter);

在这里,我们可以看到买之前我们所说的通栏布局,也就是展现一个视图的singleLayoutHelper,这里adapter就是我们上面所说的自定义的Adapter,因为每个视图对应的adapter都是不同的,所以我们需要重写onCreateViewHolderonBindViewHolder方法,然后将编写好的轮播图adapter布局添加至list结合中,至此,轮播图的界面编写完成。
下面,我们将考虑第二种布局界面的编写:网格布局 看下图

119048-18cae93d97482985.png

如图所示,上部分类导航栏就是网格布局。单个布局很简单,就是一张图片加一个TextView,

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/White"
    android:gravity="center"
    android:orientation="vertical"
    android:paddingBottom="10dp">

    <ImageView
        android:id="@+id/iv_home_one_grid_icon"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_marginTop="5dp"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/iv_home_one_grid_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/Black" />

</LinearLayout>

挺简单的,下面我们将其也添加至RecyclerView里面

//加载主页两行网格布局

        GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(4);
        GeneralVLayoutAdapter gridAdapter = new GeneralVLayoutAdapter(
                getContext(), gridLayoutHelper, 8) {
            @NonNull
            @Override
            public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
                View view = LayoutInflater.from(getContext()).inflate(
                        R.layout.home_pager_grid_two_line, viewGroup, false);
                return new MainViewHolder(view);
            }

            @Override
            public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, int i) {
                super.onBindViewHolder(mainViewHolder, i);
                ImageView imageView = mainViewHolder.itemView.findViewById(R.id.iv_home_one_grid_icon);
                TextView textView = mainViewHolder.itemView.findViewById(R.id.iv_home_one_grid_title);
                switch (i) {
                    case 0:
                        textView.setText("充值中心");
                        imageView.setImageResource(R.drawable.icon_voucher_center);
                        imageView.setOnClickListener(new MyClick(1));
                        break;
                    case 1:
                        textView.setText("手机通讯");
                        imageView.setImageResource(R.drawable.icon_phone);
                        imageView.setOnClickListener(new MyClick(2));
                        break;
                    case 2:
                        textView.setText("电影票");
                        imageView.setImageResource(R.drawable.icon_movie);
                        imageView.setOnClickListener(new MyClick(3));
                        break;
                    case 3:
                        textView.setText("全民游戏");
                        imageView.setImageResource(R.drawable.icon_game);
                        imageView.setOnClickListener(new MyClick(4));
                        break;
                    case 4:
                        textView.setText("代还信用卡");
                        imageView.setImageResource(R.drawable.icon_pay_card);
                        imageView.setOnClickListener(new MyClick(5));
                        break;
                    case 5:
                        textView.setText("现金分期");
                        imageView.setImageResource(R.drawable.icon_cash_fenqi);
                        imageView.setOnClickListener(new MyClick(6));
                        break;
                    case 6:
                        textView.setText("办信用卡");
                        imageView.setImageResource(R.drawable.icon_ban_card);
                        imageView.setOnClickListener(new MyClick(7));
                        break;
                    case 7:
                        textView.setText("全部分类");
                        imageView.setImageResource(R.drawable.icon_all_classify);
                        imageView.setOnClickListener(new MyClick(8));
                        break;
                    default:
                        break;
                }

            }
        };
        madapters.add(gridAdapter);

之前已经说明了,需要重写两个方法,就不再赘述了。这样就将网格布局添加进去了。下面是新的布局,直接上XML代码

<LinearLayout 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:orientation="vertical">

    <RelativeLayout
        android:id="@+id/rl_goods_title_layout"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginTop="10dp"
        android:background="@color/White">

        <TextView
            android:id="@+id/tv_home_goods_title_image"
            android:layout_width="5dp"
            android:layout_height="20dp"
            android:layout_alignParentStart="true"
            android:layout_centerVertical="true"
            android:layout_marginStart="10dp"
            android:background="@drawable/shape_home_goods_title" />

        <TextView
            android:id="@+id/tv_home_goods_title_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginStart="10dp"
            android:layout_toRightOf="@+id/tv_home_goods_title_image"
            android:text="活动"
            android:textColor="@color/Black"
            android:textSize="16sp" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:layout_marginEnd="10dp"
            android:src="@drawable/user_icon_arrow_right" />

    </RelativeLayout>

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/iv_home_goods_bigImage"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:scaleType="centerCrop" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:orientation="horizontal">

        <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/iv_home_goods_item_1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginEnd="0.1dp"
            android:layout_weight="1"
            android:scaleType="fitXY" />

        <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/iv_home_goods_item_2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginStart="0.1dp"
            android:layout_weight="1"
            android:scaleType="fitXY" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:layout_marginTop="0.2dp"
        android:orientation="horizontal">

        <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/iv_home_goods_item_3"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginEnd="0.1dp"
            android:layout_weight="1"
            android:scaleType="fitXY" />

        <com.facebook.drawee.view.SimpleDraweeView
            android:id="@+id/iv_home_goods_item_4"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginStart="0.1dp"
            android:layout_weight="1"
            android:scaleType="fitXY" />
    </LinearLayout>


</LinearLayout>

这个XML文件也很简单,首先是Title,然后下面是一张SimpleDraweeView,最后是四张SimpleDraweeView在一起的矩形图
我们也将其添加至recyclerView中

        int count = mHomeSortInfos.size();
        GridLayoutHelper sortHelp = new GridLayoutHelper(1);
        GeneralVLayoutAdapter sortAdapter = new GeneralVLayoutAdapter(getContext(), sortHelp, count) {
            @NonNull
            @Override
            public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
                View view = LayoutInflater.from(
                        getActivity()).inflate(R.layout.home_pager_goods_layout, viewGroup, false);
                return new MainViewHolder(view);
            }

            @Override
            public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, final int i) {
                super.onBindViewHolder(mainViewHolder, i);
                HomeSortInfo homeSortInfo = mHomeSortInfos.get(i);
                TextView textTitle = mainViewHolder.itemView.findViewById(R.id.tv_home_goods_title_text);
                textTitle.setText(homeSortInfo.getTitle());
                SimpleDraweeView draweeView = mainViewHolder.itemView.findViewById(R.id.iv_home_goods_bigImage);
                draweeView.setImageURI(homeSortInfo.getSortImageUrl());
                draweeView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        toWebActivity(UrlInfoBean.homeHeaderUrls[i]);
                    }
                });

                TextView textLeftImage = mainViewHolder.itemView.findViewById(R.id.tv_home_goods_title_image);
                switch (i) {
                    case 1:
                        textLeftImage.setBackground(getContext().getResources().getDrawable(R.drawable.shape_home_goods_title1));
                        break;
                    case 2:
                        textLeftImage.setBackground(getContext().getResources().getDrawable(R.drawable.shape_home_goods_title2));
                        break;
                    case 3:
                        textLeftImage.setBackground(getContext().getResources().getDrawable(R.drawable.shape_home_goods_title3));
                        break;
                    default:
                        break;
                }

                RelativeLayout heardLayout = mainViewHolder.itemView.findViewById(R.id.rl_goods_title_layout);
                heardLayout.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        startActivity(new Intent(getContext(), ClassifyGoodsActivity.class));
                        getActivity().overridePendingTransition(R.anim.activity_right_in, 0);
                    }
                });

                List<HomeSortItemfo> sortItemfos = homeSortInfo.getmItemfos();
                SimpleDraweeView draweeView1Item1 = mainViewHolder.itemView.findViewById(R.id.iv_home_goods_item_1);
                SimpleDraweeView draweeView1Item2 = mainViewHolder.itemView.findViewById(R.id.iv_home_goods_item_2);
                SimpleDraweeView draweeView1Item3 = mainViewHolder.itemView.findViewById(R.id.iv_home_goods_item_3);
                SimpleDraweeView draweeView1Item4 = mainViewHolder.itemView.findViewById(R.id.iv_home_goods_item_4);

                draweeView1Item1.setImageURI(sortItemfos.get(0).getGoodsImageUrl());
                draweeView1Item2.setImageURI(sortItemfos.get(1).getGoodsImageUrl());
                draweeView1Item3.setImageURI(sortItemfos.get(2).getGoodsImageUrl());
                draweeView1Item4.setImageURI(sortItemfos.get(3).getGoodsImageUrl());

                draweeView1Item1.setOnClickListener(new MyClick("iv_home_goods_item_1"));
                draweeView1Item2.setOnClickListener(new MyClick("iv_home_goods_item_2"));
                draweeView1Item3.setOnClickListener(new MyClick("iv_home_goods_item_3"));
                draweeView1Item4.setOnClickListener(new MyClick("iv_home_goods_item_4"));
            }
        };

        madapters.add(sortAdapter);

        mdelegateAdapter.setAdapters(madapters);

    }

很简单吧,这样我们的布局界面就完成了,接下来,需要通过网络获取资源文件

mHomeSortInfos = new ArrayList<>();
        mHomeSortItemfos = new ArrayList<>();
        final JsonUtil jsonUtil = new JsonUtil();
        OkHttpUtil.getInstance().startGet(UrlInfoBean.homeGoodsUrl, new OnNetResultListener() {
            @Override
            public void OnSuccessListener(String result) {
                LogUtil.d("LF1234", "result=" + result);
                mHomeSortInfos = jsonUtil.getDataFromJson(result, 0);
                LogUtil.d("LF123", "mHomeSortInfos=" + mHomeSortInfos);
                Message message = mHandler.obtainMessage(0x01, mHomeSortInfos);
                mHandler.sendMessage(message);
            }

ok,下面看下效果如何。

图片发自简书App

嗯,有些缺陷,轮播图的图片还没有显示出来,但是大体的功能界面已经完成,后期会改进,欢迎大家评论,留言,指导,感谢大家的阅读,谢谢!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容