1. 程式人生 > >recyclerView 實現複雜的item佈局(如淘寶、京東、商城類首頁)

recyclerView 實現複雜的item佈局(如淘寶、京東、商城類首頁)

前言

現在各種電商如火如荼,首頁頁面設計也頗有色彩。
之前專案也是一個電商類購物app,主頁設計了好幾套樣式。
其中一個樣式如下圖相似涉及到: 輪播廣告圖bannerviewPager的輪播沉浸式狀態列
recyclerView的item的複雜分割線以及自定義的主頁頭條ViewFlipper使用glide圖片載入、其他的瑣碎知識點也略有涉及到。

看下Gif效果圖:

1

再下引用的第三方控制元件:

     //banner
    implementation 'com.youth.banner:banner:1.4.10'
    //RecyclerView
    implementation
'com.android.support:recyclerview-v7:27.1.1' //RecyclerView Adapter implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.40' //圖片載入 implementation 'com.github.bumptech.glide:glide:3.7.0' //沉浸式 implementation 'com.jaeger.statusbarutil:library:1.5.1' //retrofit2 轉化器 gson
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
HomeFragment基本程式碼

這裡主要說一下:recyclerView的item的複雜分割線

根據GridLayoutManagergetSpanSize()方法可以動態的設定item跨列數;

 mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 6));
  • return 6表示獨佔一個item 比如一張圖片佔滿一行
  • return 3 3是6的多少?2分之1啊,那就是佔一行的一半 也就是說 如果放圖片 一行可以最大放2張!!!
  • return 2 2是6的多少?3分之1啊,那就是佔一行的3分之1 也就是說 如果放圖片 一行可以最大放3張!!!

例如:
根據getItemViewType返回的itemtype,第一個position顯示為輪播圖,
所以返回的是gridManager.getSpanCount(); 即:return 6
如果是2張圖佔滿一行,那麼1張圖就是佔整行的二分之一,既6/2=3, return 3即可。

public class HomeFragment extends BaseFragment {
    private LinearLayout mToolbar;
    private RecyclerView mRecyclerView;
    private List<TestBean> data;
    private int height;

    @Override
    public int getLayoutId() {
        return R.layout.app_fragment_home;
    }

    @Override
    public void initView(View mView) {
        mToolbar = mView.findViewById(R.id.toolbar);
        mRecyclerView = mView.findViewById(R.id.app_home_list);
    }

     /**
     * 懶載入方法    
     */
    @Override
    public void lazyLoad() {
        GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), 6);
        mRecyclerView.setLayoutManager(gridLayoutManager);
        String jsonData = new String(getAssertsFile(getContext(), "content.json"));
        data = new Gson().fromJson(jsonData, new TypeToken<List<TestBean>>() {
        }.getType());
        TestHomeAdapter adapter = new TestHomeAdapter();
        //這裡就要設定分割線了
        adapter.setSpanSizeLookup(new BaseQuickAdapter.SpanSizeLookup() {
            @Override
            public int getSpanSize(GridLayoutManager gridLayoutManager, int position) {
                int type = data.get(position).getType();
                if (type == 1 || type == 3 || type == 2 || type == 5 || type == 6) {
                    return 6;
                } else if (type == 4) {
                    return 2;
                } else if (type == 7) {
                    return 3;
                }
                return 0;
            }
        });
        mRecyclerView.setAdapter(adapter);
        adapter.setHeaderView(getHeaderView(mRecyclerView));
        adapter.setNewData(data);
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            private int totalDy = 0;

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                totalDy += dy;
                if (totalDy <= height) {
                    float alpha = (float) totalDy / height;
                    mToolbar.setBackgroundColor(ColorUtils.blendARGB(Color.TRANSPARENT
                            , ContextCompat.getColor(getContext(), R.color.white), alpha));
                } else {
                    mToolbar.setBackgroundColor(ColorUtils.blendARGB(Color.TRANSPARENT
                            , ContextCompat.getColor(getContext(), R.color.white), 1));
                }
            }
        });
    }

    /**
     * 輪播圖banner的資料設定
     */
    private View getHeaderView(RecyclerView v) {
        List<String> bannerImg = new ArrayList<>();
        bannerImg.add("圖片地址1.jpg");
        bannerImg.add("圖片地址2.jpg");
        bannerImg.add("圖片地址3.jpg");
        bannerImg.add("http://58.87.71.247:8080/TestFile/banner.png");
        View convertView = LayoutInflater
                .from(getContext())
                .inflate(R.layout.app_include_home_header, (ViewGroup) v.getParent(), false);
        Banner mBanner = convertView.findViewById(R.id.app_home_header_banner);
        mBanner.setImages(bannerImg)
                .setImageLoader(new GlideImageLoader())
                .setDelayTime(3000)
                .start();


        MarqueeView marqueeView = convertView.findViewById(R.id.app_home_header_problem);

        //頭條資料ViewFlipper
        List<String> problems = new ArrayList<>();
        problems.add("如何獲取更多個人積分");
        problems.add("下單時服務費率規則");
        problems.add("大額預定商品詳細交易流程");
        marqueeView.startWithList(problems);

        ViewGroup.LayoutParams bannerParams = mBanner.getLayoutParams();
        int resourceId = getContext().getResources().getIdentifier("status_bar_height", 
        "dimen","android");
        int statusBarHeight = getContext().getResources().getDimensionPixelSize(resourceId);
        height = bannerParams.height - statusBarHeight - 104;
        return convertView;
    }

    //模擬後臺請求資料 存放在AssertsFile資料夾裡
    public static byte[] getAssertsFile(Context context, String fileName) {
        InputStream inputStream = null;
        //讀取資源
        AssetManager assetManager = context.getAssets();
        try {
            inputStream = assetManager.open(fileName);
            if (inputStream == null) {
                return null;
            }

            BufferedInputStream bis = null;
            int length;
            try {
                bis = new BufferedInputStream(inputStream);
                length = bis.available();
                byte[] data = new byte[length];
                bis.read(data);

                return data;
            } catch (IOException e) {

            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (Exception e) {

                    }
                }
            }

            return null;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}
基類Fragment
public abstract class BaseFragment extends Fragment {

    View mView;
    boolean isLoad = false;
    boolean isInit = false;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        if (mView == null)
            mView = inflater.inflate(getLayoutId(), container, false);
        isInit = true;
        initView(mView);
        isCanLoadData();
        return mView;
    }

    public abstract void initView(View mView);

    /**
     * 檢視是否已經對使用者可見,系統的方法
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        isCanLoadData();
    }

    /**
     * 懶載入
     */
    private void isCanLoadData() {
        if (!isInit) {
            return;
        }
        if (getUserVisibleHint() && !isLoad) {
            lazyLoad();
            isLoad = true;
        } else {
            if (isLoad) {
                stopLoad();
            }
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        isInit = false;
    }


    /**
     * 第一次載入的處理   此處可以留給載入網路去處理
     */
    public void lazyLoad() {

    }

    /**
     * 頁面停止載入的處理
     */
    public void stopLoad() {

    }

    public abstract int getLayoutId();

}
核心adapter
public class TestHomeAdapter extends MultipleItemRvAdapter<TestBean, BaseViewHolder> {
    //通欄商品大圖片
    public static final int TYPE_IMG = 100;
    //通欄圖文
    public static final int TYPE_TEXT_AND_IMG = 200;
    //通欄文字
    public static final int TYPE_TEXT = 300;
    //三列
    public static final int TYPE_THREE_COLUMN = 400;
    //通欄水平拖動
    public static final int TYPE_HORIZONTAL_SCROLL = 500;
    //通欄窄圖片
    public static final int TYPE_NARROW_IMG = 600;
    //兩列
    public static final int TYPE_TWO_COLUMN = 700;
    public TestHomeAdapter() {
        super(null);
        finishInitialize();
    }

    @Override
    protected int getViewType(TestBean testBean) {
        int type = testBean.getType();
        if (type == 1) {
            return TYPE_IMG;
        } else if (type == 2) {
            return TYPE_TEXT_AND_IMG;
        } else if (type == 3) {
            return TYPE_TEXT;
        } else if (type == 4) {
            return TYPE_THREE_COLUMN;
        } else if (type == 5) {
            return TYPE_HORIZONTAL_SCROLL;
        } else if (type == 6) {
            return TYPE_NARROW_IMG;
        } else if (type == 7) {
            return TYPE_TWO_COLUMN;
        }
        return 0;
    }

    @Override
    public void registerItemProvider() {
        //通欄商品大圖片
        mProviderDelegate.registerProvider(new ImgItemProvider());
        //通欄圖文
        mProviderDelegate.registerProvider(new ImgAndTextItemProvider());
        //通欄文字
        mProviderDelegate.registerProvider(new TextItemProvider());
        //三列圖文
        mProviderDelegate.registerProvider(new ThreeColumnItemProvider());
        //通欄橫向滑動
        mProviderDelegate.registerProvider(new ScrollItemProvider());
        //通欄窄圖片
        mProviderDelegate.registerProvider(new NarrowImgItemProvider());
        //兩列圖文
        mProviderDelegate.registerProvider(new TwoColumnItemProvider());
    }
}
demo地址:
與君共勉

我要一步一步往上爬
在最高點乘著葉片往前飛
任風吹乾流過的淚和汗
我要一步一步往上爬
等待陽光靜靜看著它的臉
小小的天有大大的夢想
我有屬於我的天
任風吹乾流過的淚和汗
總有一天我有屬於我的天
這裡寫圖片描述