关于MallFragment页面编写

之前已经详细讲述了主页面的编写,有疑问的小伙伴可以点此处https://www.jianshu.com/p/e9f08581b514
Mall商城页面编写大致差不多,有些相同的地方就不在赘述了,下面看代码

<?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:id="@+id/swipe_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_fragment_mall_context"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/White"
            android:clipToPadding="true"
            android:descendantFocusability="blocksDescendants"
            android:paddingLeft="0dp"
            android:paddingRight="0dp"
            android:requiresFadingEdge="none"
            android:scrollbars="none" />
    </android.support.v4.widget.SwipeRefreshLayout>

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar_mall"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorYellow"
        app:layout_behavior="lf.com.android.blackfishdemo.util.MallBarAlphaBehavior">

        <RelativeLayout
            android:id="@+id/rl_mall_header"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="20dp">

            <ImageView
                android:id="@+id/iv_mall_heard_menu"
                android:layout_width="25dp"
                android:layout_height="25dp"
                android:layout_centerVertical="true"
                android:layout_marginTop="10dp"
                android:scaleType="fitXY"
                android:src="@drawable/stages_icon_classify_white" />

            <RelativeLayout
                android:id="@+id/rl_mall_head_layout"
                android:layout_width="match_parent"
                android:layout_height="25dp"
                android:layout_centerVertical="true"
                android:layout_marginEnd="40dp"
                android:layout_marginStart="10dp"
                android:layout_marginTop="12.5dp"
                android:layout_toEndOf="@+id/iv_mall_heard_menu"
                android:background="@drawable/shape_search_view">

                <ImageView
                    android:id="@+id/iv_search_logo"
                    android:layout_width="15dp"
                    android:layout_height="15dp"
                    android:layout_centerVertical="true"
                    android:layout_marginStart="10dp"
                    android:src="@drawable/stages_icon_search" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_marginStart="10dp"
                    android:layout_toRightOf="@id/iv_search_logo"
                    android:background="@color/color_rv_bg"
                    android:hint="HuaWei P10"
                    android:textSize="13sp" />
            </RelativeLayout>

            <ImageView
                android:id="@+id/iv_mall_header_msg"
                android:layout_width="20dp"
                android:layout_height="20dp"
                android:layout_alignParentEnd="true"
                android:layout_centerVertical="true"
                android:layout_marginEnd="10dp"
                android:layout_marginTop="12.5dp"
                android:src="@drawable/icon_home_header_msg_white" />

        </RelativeLayout>

    </android.support.v7.widget.Toolbar>

</android.support.design.widget.CoordinatorLayout>

布局是由Toolbar和RecyclerView组成的。和之前的并没有什么差异,
也是需要配置adapter,只是布局不同罢了,其他的都是大同小异
这里需要注意的是behavior,什么是behavior?
Behavior就是执行你定制的动作。Interaction behavior plugin for child views of CoordinatorLayout. 作用于CoordinatorLayout的子View的交互行为插件。一个Behavior 实现了用户的一个或者多个交互行为,它们可能包括拖拽、滑动、快滑或者其他一些手势。在讲Behavior之前必须先理解两个概念:Child和Dependency,什么意思呢?Child当然是子View的意思了,是谁的子View呢,当然是CoordinatorLayout的子View;其实Child是指要执行动作的CoordinatorLayout的子View。而Dependency是指Child依赖的View。如过Dependency这个View发生了变化,那么Child这个View就要相应发生变化。发生变化是具体发生什么变化呢?这里就要引入Behavior,Child发生变化的具体执行的代码都是放在Behavior这个类里面。
Behavior 是一个顶层抽象类,其他的一些具体行为的Behavior 都是继承自这个类。它提供了几个重要的方法:

  • layoutDependsOn
     /**
     * 表示是否给应用了Behavior 的View 指定一个依赖的布局,通常,当依赖的View 布局发生变化时
     * 不管被被依赖View 的顺序怎样,被依赖的View也会重新布局
     * @param parent
     * @param child 绑定behavior 的View
     * @param dependency   依赖的view
     * @return 如果child 是依赖的指定的View 返回true,否则返回false
     */
    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return super.layoutDependsOn(parent, child, dependency);
    }
  • onDependentViewChanged
     /**
     * 当被依赖的View 状态(如:位置、大小)发生变化时,这个方法被调用
     * @param parent
     * @param child
     * @param dependency
     * @return
     */
    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        return super.onDependentViewChanged(parent, child, dependency);
    }
  • onStartNestedScrol
     /**
     *  当coordinatorLayout 的子View试图开始嵌套滑动的时候被调用。当返回值为true的时候表明
     *  coordinatorLayout 充当nested scroll parent 处理这次滑动,需要注意的是只有当返回值为true
     *  的时候,Behavior 才能收到后面的一些nested scroll 事件回调(如:onNestedPreScroll、onNestedScroll等)
     *  这个方法有个重要的参数nestedScrollAxes,表明处理的滑动的方向。
     *
     * @param coordinatorLayout 和Behavior 绑定的View的父CoordinatorLayout
     * @param child  和Behavior 绑定的View
     * @param directTargetChild
     * @param target
     * @param nestedScrollAxes 嵌套滑动 应用的滑动方向,看 {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
     *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL}
     * @return
     */
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
        return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }
  • onNestedPreScroll
     /**
     * 嵌套滚动发生之前被调用
     * 在nested scroll child 消费掉自己的滚动距离之前,嵌套滚动每次被nested scroll child
     * 更新都会调用onNestedPreScroll。注意有个重要的参数consumed,可以修改这个数组表示你消费
     * 了多少距离。假设用户滑动了100px,child 做了90px 的位移,你需要把 consumed[1]的值改成90,
     * 这样coordinatorLayout就能知道只处理剩下的10px的滚动。
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dx  用户水平方向的滚动距离
     * @param dy  用户竖直方向的滚动距离
     * @param consumed
     */
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
    }
  • onNestedScroll
     /**
     * 进行嵌套滚动时被调用
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dxConsumed target 已经消费的x方向的距离
     * @param dyConsumed target 已经消费的y方向的距离
     * @param dxUnconsumed x 方向剩下的滚动距离
     * @param dyUnconsumed y 方向剩下的滚动距离
     */
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
    }
  • onStopNestedScroll
     /**
     *  嵌套滚动结束时被调用,这是一个清除滚动状态等的好时机。
     * @param coordinatorLayout
     * @param child
     * @param target
     */
    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) {
        super.onStopNestedScroll(coordinatorLayout, child, target);
    }
  • onNestedScrollAccepted
      /**
     * onStartNestedScroll返回true才会触发这个方法,接受滚动处理后回调,可以在这个
     * 方法里做一些准备工作,如一些状态的重置等。
     * @param coordinatorLayout
     * @param child
     * @param directTargetChild
     * @param target
     * @param nestedScrollAxes
     */
    @Override
    public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
        super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }
  • onNestedPreFling
     /**
     * 用户松开手指并且会发生惯性动作之前调用,参数提供了速度信息,可以根据这些速度信息
     * 决定最终状态,比如滚动Header,是让Header处于展开状态还是折叠状态。返回true 表
     * 示消费了fling.
     *
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param velocityX x 方向的速度
     * @param velocityY y 方向的速度
     * @return
     */
    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY) {
        return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
    }
  • onLayoutChild
      //可以重写这个方法对子View 进行重新布局
    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
        return super.onLayoutChild(parent, child, layoutDirection);
    }

ok,大家对behavior有了一定的认识后,我们来去看下自定义behavior怎么去编写吧

public class MallBarAlphaBehavior extends CoordinatorLayout.Behavior<Toolbar> {
    private int offset = 0;
    private int startOffset = 0;
    private int endOffset = 0;
    private Context mContext;

    public MallBarAlphaBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull Toolbar child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
        return true;
    }

    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull Toolbar child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        startOffset = 0;
        endOffset = child.getHeight();//返回子视图的高度
        offset += dyConsumed;//叠加在Y轴上消耗的距离
        RelativeLayout relativeLayout = (RelativeLayout) child.getChildAt(0);
        ImageView imageMenu = (ImageView) relativeLayout.getChildAt(0);//获取指定视图
        ImageView imageMsg = (ImageView) relativeLayout.getChildAt(2);//获取指定视图

        if (offset <= startOffset) {//如果Y轴上消耗的距离<=0的话,就将子view透明度设置为0
            child.getBackground().setAlpha(0);
        } else if (offset > startOffset && offset < endOffset) {//如果滑动的距离大于0,并且滑动范围在子view视图里面
            imageMsg.setImageDrawable(mContext.getResources().getDrawable(R.drawable.icon_home_header_msg_white));
            imageMenu.setImageDrawable(mContext.getResources().getDrawable(R.drawable.stages_icon_classify_white));
            float precent = (float) (offset - startOffset) / endOffset;
            int alpha = Math.round(precent * 255);
            child.getBackground().setAlpha(alpha);

            imageMenu.getDrawable().setAlpha(1 - alpha);
            imageMsg.getDrawable().setAlpha(1 - alpha);

        } else if (offset >= endOffset) {//滑动距离超过了子veiw的范围
            child.getBackground().setAlpha(255);
            imageMsg.setImageDrawable(mContext.getResources().getDrawable(R.drawable.icon_home_header_msg_black));
            imageMenu.setImageDrawable(mContext.getResources().getDrawable(R.drawable.stages_icon_classify_gray));
            imageMenu.setVisibility(View.VISIBLE);
            imageMenu.setAlpha(1f);
            imageMsg.setVisibility(View.VISIBLE);
            imageMsg.setAlpha(1f);
        }
    }
}

可以看到首先我们需要将onStartNestedScroll返回值设置为true,才能让behavior拦截到后续的方法。思路大致是监听onNestedScroll方法,因为,只要控件产生位移,就会调用此方法,首先定义三个变量,
startOffset表示控件未产生滑动的时候位置,endOffset表示子控件在视图中的高度,offset表示累加当前滑动距离。如果当前滑动距离小于等于0时候,我们可以认为控件是静止的,因为这里并不是相对滑动,而是绝对滑动,不存在负值,继而我们判断滑动时候的状态,滑动是否在我们子控件的范围内还是超出了子控件的范围,分别写上不同的逻辑。这样,我们的behavior就写好了,我们在之前的XML文件中已经添加过了,就是这行代码

app:layout_behavior="lf.com.android.blackfishdemo.util.MallBarAlphaBehavior">

下面展示一下效果


图片发自简书App

注意我们的标题栏,是不是变色了,哈哈。接下来的代码和之前的商城商城页面代码也没有啥区别,首先是轮播图的代码

 final SingleLayoutHelper layoutHelper = new SingleLayoutHelper();
        GeneralVLayoutAdapter bannerAdapter = new GeneralVLayoutAdapter(mContext, layoutHelper, 1) {
            @NonNull
            @Override
            public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
                View view = LayoutInflater.from(
                        mContext).inflate(R.layout.mall_pager_banner_layout, viewGroup, false);

                return new MainViewHolder(view);
            }


            @Override
            public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, int i) {
                super.onBindViewHolder(mainViewHolder, i);
                mBanner = mainViewHolder.itemView.findViewById(R.id.rvb_mall_header);
                mBannerInfos = mallPagerInfo.getmBannerInfos();
                mBanner.setRvBannerData(mBannerInfos);
                mBanner.setOnSwitchRvBannerListener(new OnSwitchRvBannerListener() {
                    @Override
                    public void switchBanner(int position, SimpleDraweeView draweeView) {
                        draweeView.setImageURI(mBannerInfos.get(position).getUrl());
                    }
                });
                mBanner.setListener(new OnRvBannerClickListener() {
                    @Override
                    public void OnClick(int position) {
                        Intent intent = new Intent(mContext, BaseWebViewActivity.class);
                        intent.putExtra("loadUrl", "https://github.com/LF1165339017");
                        startActivity(intent);
                        getActivity().overridePendingTransition(R.anim.activity_right_in, 0);
                    }
                });
            }

        };
        adapters.add(bannerAdapter);

这里还是一样要重写 onCreateViewHolderonBindViewHolder方法,先引入布局,然后获取数据源填充进轮播图里面.这里需要注意是我们自定义了一个接口用来设置轮播图片和监听点击事件,轮播图在之前有详细讲解,如果有需要跟深入了解轮播图请点击。Ok,下面开始编写新的代码。

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


            @Override
            public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, final int i) {
                super.onBindViewHolder(mainViewHolder, i);
                mImageGridItem = mainViewHolder.itemView.findViewById(R.id.iv_mall_grid_item);
                mTextGridItem = mainViewHolder.itemView.findViewById(R.id.tv_mall_grid_item);
                mGridInfos = mallPagerInfo.getmClassifyInfo();
                mImageGridItem.setImageURI(mGridInfos.get(i).getImageUrl());
                mTextGridItem.setText(mGridInfos.get(i).getTitle());

                mImageGridItem.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        listener.onItemClick("ClassifyGridItem" + i);
                    }
                });
            }
        };
        adapters.add(gridAdapter);

这段代码也很简单,这是一个网格布局,我们设定为5列,

GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(5)

然后adapter中添加子view的个数

GeneralVLayoutAdapter gridAdapter = new GeneralVLayoutAdapter(mContext, gridLayoutHelper, 10){}

并重写onCreateViewHolderonBindViewHolder这两种方法,也没有啥好说的,比较简单,就不在赘述了。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="10dp">

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/iv_four_header_image"
        android:layout_width="match_parent"
        android:layout_height="80dp" />

    <lf.com.android.blackfishdemo.view.GridViewForScroll
        android:id="@+id/gv_four_goods"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:numColumns="2"
        android:paddingStart="5dp"
        android:horizontalSpacing="2dp"
        android:verticalSpacing="2dp"
        android:stretchMode="columnWidth"
        android:layout_below="@+id/iv_four_header_image"
        />
</RelativeLayout>

这段XML文件也比较简单,使用的SimpleDrawweeView和自定义的GridViewForScroll,SimpleDraweeView是用来放图片的,那么来看看GridViewForScoll用途。

package lf.com.android.blackfishdemo.view;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.GridView;

public class GridViewForScroll extends GridView {
    public GridViewForScroll(Context context) {
        super(context);
    }

    public GridViewForScroll(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public GridViewForScroll(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec + 30);
    }
}

这里我们继承GridView并重写了三个构造方法,这个没啥好说的。重点时是 onMeasure这个方法,它是自定义View的测量过程,关于自定义view的方法,请点击这里
这里会重写onMeasure方法是因为在一般情况下使用GridView、listView其实都是高度填充父类窗体(fill_parent、match_parent),那么UI显示正常,不过,当在这个外面嵌套一个垂直方向滚动的布局(ScrollView)之后,特殊情况就出现了。listview的滑动冲突。gridView的显示一行等
大概的意思是能获取到测量的View的高度,然后+30dp,保证控件的上下间距。就不再深究了。

        SingleLayoutHelper fourGoodsHelper = new SingleLayoutHelper();
        GeneralVLayoutAdapter fourGoodsAdapter = new GeneralVLayoutAdapter(mContext, fourGoodsHelper, 1) {
            @NonNull
            @Override
            public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {

                View view = LayoutInflater.from(mContext).inflate(
                        R.layout.mall_pager_four_goods_layout, viewGroup, false);
                return new MainViewHolder(view);
            }


            @Override
            public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, int i) {
                super.onBindViewHolder(mainViewHolder, i);

                SimpleDraweeView headerImage = mainViewHolder.itemView.findViewById(R.id.iv_four_header_image);
                GridViewForScroll gridFourGoods = mainViewHolder.itemView.findViewById(R.id.gv_four_goods);
                gridFourGoods.setAdapter(new GridOnlyImageAdapter(mContext, mallPagerInfo.getmGridGoodsInfos()));
                headerImage.setImageURI(mallPagerInfo.getSingleImageUrl());

                headerImage.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        listener.onItemClick("SingleHeaderImage");
                    }
                });
            }
        };
        adapters.add(fourGoodsAdapter);


        GridLayoutHelper gridHotClassifyHelper = new GridLayoutHelper(1);
        GeneralVLayoutAdapter hotClassifyAdapter = new GeneralVLayoutAdapter(
                mContext, gridHotClassifyHelper, mallPagerInfo.getmMallGoodsInfos().size()) {
            @NonNull
            @Override
            public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
                View view = LayoutInflater.from(mContext).inflate(
                        R.layout.mall_pager_hot_classify_grid_layout, viewGroup, false);
                return new MainViewHolder(view);
            }

            @Override
            public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, final int i) {
                super.onBindViewHolder(mainViewHolder, i);
                List<MallHotClassifyGridInfo> mallHotClassifyGridInfos = new ArrayList<>();
                SimpleDraweeView headerImage = mainViewHolder.itemView.findViewById(R.id.iv_hot_classify_header_image);
                GridViewForScroll gridGoods = mainViewHolder.itemView.findViewById(R.id.gv_hot_classify);
                List<MallGoodsInfo> mallGoodsInfos = mallPagerInfo.getmMallGoodsInfos();
                headerImage.setImageURI(mallGoodsInfos.get(i).getHeadImageUrl());
                headerImage.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        listener.onItemClick("HotGoodsHeaderImage" + i);
                    }
                });

                int itemSize = mallGoodsInfos.get(i).getmMallGoodsItemInfos().size();

                for (int j = 0; j < itemSize; j++) {
                    MallGoodsItemInfo mallGoodsItemInfo = mallGoodsInfos.get(i).getmMallGoodsItemInfos().get(i);
                    String goodsImage = mallGoodsItemInfo.getImageUrl();
                    String goodsDesc = mallGoodsItemInfo.getDesc();
                    String goodsPeriods = "¥" + mallGoodsItemInfo.getSinglePrice()
                            + " x " + mallGoodsItemInfo.getPeriods() + "期";
                    String goodsPrice = "¥" + mallGoodsItemInfo.getPrice();
                    mallHotClassifyGridInfos.add(new MallHotClassifyGridInfo(goodsImage, goodsDesc, goodsPeriods, goodsPrice));
                }

                MallHotClassifyGridAdapter adapter = new MallHotClassifyGridAdapter(mContext, mallHotClassifyGridInfos);
                adapter.setmOnViewItemClickListener(onViewItemClickListener);
                gridGoods.setAdapter(adapter);

            }
        };

        adapters.add(hotClassifyAdapter);

这一段代码和上面大同小异,也就不再深究了,我们主要来看下面这一段代码

        final SingleLayoutHelper recoHelper = new SingleLayoutHelper();
        GeneralVLayoutAdapter recoAdapter = new GeneralVLayoutAdapter(mContext, recoHelper, 1) {
            @NonNull
            @Override
            public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
                View view = LayoutInflater.from(mContext).inflate(R.layout.mall_pager_recommend_goods_list, viewGroup, false);
                return new MainViewHolder(view);
            }


            @Override
            public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, int i) {
                super.onBindViewHolder(mainViewHolder, i);
                RecyclerView recyclerView = mainViewHolder.itemView.findViewById(R.id.rv_mall_recommend);
                List<RecommendGoodsInfo> recommendGoodsInfos = mallPagerInfo.getmRecommendGoodsInfos();
                recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
                recyclerView.addItemDecoration(new DividerItemDecoration(mContext, DividerItemDecoration.VERTICAL));
                recyclerView.setAdapter(new RecommendGoodsAdapter(mContext, recommendGoodsInfos));
            }
        };
        adapters.add(recoAdapter);

上面的代码格式还是大同小异,我们来看下布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

        <ImageView
            android:layout_width="80dp"
            android:layout_height="8dp"
            android:layout_alignParentStart="true"
            android:layout_centerVertical="true"
            android:layout_marginStart="70dp"
            android:src="@drawable/icon_recommend_title_left" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="为你推荐"
            android:textColor="@color/Black"
            android:textSize="18sp" />

        <ImageView
            android:layout_width="80dp"
            android:layout_height="8dp"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:layout_marginEnd="70dp"
            android:src="@drawable/icon_recommend_title_right" />
    </RelativeLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_mall_recommend"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/rl_mall_recommend_title_layout"
        android:layout_marginBottom="30dp"
        android:background="@color/White" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_below="@+id/rv_mall_recommend">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:gravity="center_horizontal|bottom"
            android:text="----------  已经到底了  ------------"
            android:textColor="@color/Black"
            android:textSize="12sp" />

    </FrameLayout>
</RelativeLayout>

这里的布局也很简单,一个头部Title+RecyclerView+底部Title,没啥好说的,我们来关注下RecyclerView的adapter布局吧。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="150dp"
    android:background="@color/White">

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/iv_mall_recommend_goods_image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerVertical="true"
        android:layout_marginStart="25dp" />

    <TextView
        android:id="@+id/tv_mall_recommend_goods_desc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="30dp"
        android:layout_toRightOf="@+id/iv_mall_recommend_goods_image"
        android:ellipsize="end"
        android:maxLines="2"
        android:textColor="@color/Black" />

    <TextView
        android:id="@+id/tv_mall_recommend_goods_price"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_mall_recommend_goods_desc"
        android:layout_marginStart="10dp"
        android:layout_marginTop="20dp"
        android:layout_toRightOf="@+id/iv_mall_recommend_goods_image"
        android:maxLines="1"
        android:text="¥27.72x12期 ¥298.00"
        android:textColor="@color/Black" />

    <TextView
        android:id="@+id/tv_mall_recommend_goods_evaluation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/iv_mall_recommend_goods_image"
        android:layout_centerHorizontal="true"
        android:background="@drawable/shape_evaluation_text"
        android:paddingBottom="2dp"
        android:paddingEnd="10dp"
        android:paddingStart="10dp"
        android:paddingTop="2dp"
        android:text="好评率:99%"
        android:textColor="@color/Black"
        android:textSize="12sp" />

</RelativeLayout>

这里的布局是一个SimpleView配上简介效果,类似于商品简介

···
截图

OK,大致的界面就编写完成了,贴上adapter的代码。
public class RecommendGoodsAdapter extends RecyclerView.Adapter<RecommendGoodsAdapter.MyViewHolder> {
    private Context mContext;
    private List<RecommendGoodsInfo> mGoodsInfos;
    private SpannableStringUtil mStringUtil;

    public RecommendGoodsAdapter(Context mContext, List<RecommendGoodsInfo> mGoodsInfos) {
        mStringUtil = new SpannableStringUtil();
        this.mContext = mContext;
        this.mGoodsInfos = mGoodsInfos;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        return new MyViewHolder(LayoutInflater.from(mContext).inflate(
                R.layout.mall_pager_recommend_goods_list_item, viewGroup, false));
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int i) {
        RecommendGoodsInfo goodsInfo = mGoodsInfos.get(i);
        myViewHolder.mDraweeView.setImageURI(goodsInfo.getImageUrl());
        myViewHolder.mTextDesc.setText(goodsInfo.getDesc());
        String price = "¥" + goodsInfo.getSinglePrice() + " x" + goodsInfo.getPeriods() + "期" + "+  ¥" + goodsInfo.getTotalPrice();
        SpannableString spannableString = mStringUtil.setMallGoodsPrice(price, 0, getFirstSpaceIndex(price.toCharArray()));
        myViewHolder.mTextPrice.setText(spannableString);
        String evaluation = "好评率:" + goodsInfo.getEvaluation();
        myViewHolder.mTextEvaluation.setText(evaluation);
    }

    @Override
    public int getItemCount() {
        return mGoodsInfos.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        private SimpleDraweeView mDraweeView;
        private TextView mTextDesc;
        private TextView mTextPrice;
        private TextView mTextEvaluation;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            mDraweeView = itemView.findViewById(R.id.iv_mall_recommend_goods_image);
            mTextDesc = itemView.findViewById(R.id.tv_mall_recommend_goods_desc);
            mTextPrice = itemView.findViewById(R.id.tv_mall_recommend_goods_price);
            mTextEvaluation = itemView.findViewById(R.id.tv_mall_recommend_goods_evaluation);
        }
    }

    private int getFirstSpaceIndex(char[] text) {
        for (int i = 0; i < text.length; i++) {
            if (text[i] == ' ') {
                return i;
            }
        }
        return 0;
    }
}

这里的RecyclerView的adapter还是很简单的,同样是重写onCreateViewHolder,onBindViewHolder,并创建自己的ViewHolder去继承RecyclerView.ViewHolder,没啥好说的,都是套路了.
最后附上界面效果


gif

感谢大家的阅读,你的建议就是我前进的动力。热爱生活,热爱开发,愿与大家一同进步。

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

推荐阅读更多精彩内容