游戏社区App (五):首页布局与数据整理

一、序言:

首页需要的大概的效果:
游戏社区App (五):首页布局与数据整理_第1张图片

二、RecyclerView控件

首先内容页面使用RecyclerView控件。
RecyclerView是一个强大的滑动组件。

RecyclerView的四大主要组成是
* Layout Manager:Item的布局。
* Adapter:为Item提供数据。
* Item Decoration:Item之间的Divider。
* Item Animator:添加、删除Item动画。

1、Layout Manager 布局管理器

RecyclerView提供了三种布局
1)、LinerLayoutManager
以垂直或者水平列表方式展示Item
2)、GridLayoutManager
以网格方式展示Item
3)、StaggeredGridLayoutManager
以瀑布流方式展示Item
4)、自定义
继承实现自己的 LayoutManager,并重写相应的方法

游戏社区App内容页面使用GridLayoutManager网格布局。
GridLayoutManager构造函数和参数含义

GridLayoutManager(Context context, int spanCount, int orientation,boolean reverseLayout)

spanCount:每行item的个数
orientation:方向,OrientationHelper.HORIZONTA 或者 OrientationHelper.VERTICAL
reverseLayout:是否逆向,true:布局逆向展示,false:布局正向显示

2、Adapter 适配器

功能就是为RecyclerView提供数据。
这里可以使用万能适配器–BaseRecyclerViewAdapterHelper

1)、BaseRecyclerViewAdapterHelper的使用:

首先在build.gradle中添加依赖

api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.16'

并且在工程的build.gradle中添加

allprojects {
    repositories {
    ...
        maven { url "https://jitpack.io" }
        google()
        jcenter()
    ...
    }}
2)、先新建MultipleItemEntity实现MultiItemEntity
public class MultipleItemEntity implements MultiItemEntity {

    private final ReferenceQueue<LinkedHashMap<Object, Object>> ITEM_QUEUE=new ReferenceQueue<>();
    private final LinkedHashMap<Object, Object> MUITIPLE_FIELDS=new LinkedHashMap<>();
    private final SoftReference<LinkedHashMap<Object, Object>> FIELDS_REFERENCE=
            new SoftReference<>(MUITIPLE_FIELDS,ITEM_QUEUE);

    public MultipleItemEntity(LinkedHashMap<Object, Object> fields){
        FIELDS_REFERENCE.get().putAll(fields);
    }

    public static MultipleItemEntityBuilder builder(){
        return new MultipleItemEntityBuilder();
    }

    @Override
    public int getItemType() {
        return (int) FIELDS_REFERENCE.get().get(MultipleFields.ITEM_TYPE);
    }

    @SuppressWarnings("unchecked")
    public final <T> T getField(Object key){
        return (T) FIELDS_REFERENCE.get().get(key);
    }

    public final LinkedHashMap<?,?> getFields(){
        return FIELDS_REFERENCE.get();
    }

    public final MultiItemEntity setField(Object key, Object value){
        FIELDS_REFERENCE.get().put(key, value);
        return this;
    }
}
3)、再新建MultipleRecyclerAdapter继承BaseMultiItemQuickAdapter
public class MultipleRecyclerAdapter extends BaseMultiItemQuickAdapter<MultipleItemEntity,MultIpleViewHolder>
        implements BaseQuickAdapter.SpanSizeLookup,
        OnItemClickListener {

    private boolean mIsInitBanner=false;//确保初始化一次banner,防止重复item加载
    private static int bannerPosition=0;//banner轮播图的序号

    protected MultipleRecyclerAdapter(List<MultipleItemEntity> data) {
        super(data);
        init();
    }

    public static MultipleRecyclerAdapter create(List<MultipleItemEntity> data){
        return new MultipleRecyclerAdapter(data);
    }

    public static MultipleRecyclerAdapter create(DataConverter converter){
        return new MultipleRecyclerAdapter(converter.convert());
    }

    private void init(){
        //对不同的ItemType设置对应的布局
        addItemType(ItemType.TITLE, R.layout.item_multiple_title);
        addItemType(ItemType.BUTTON, R.layout.item_multiple_button);
        addItemType(ItemType.BANNER, R.layout.item_multiple_banner);
                .......(省略)

        //设置宽度的监听
        setSpanSizeLookup(this);
        //使用动画
        openLoadAnimation();
        //不多次执行动画
        isFirstOnly(false);
    }

    @Override
    protected MultIpleViewHolder createBaseViewHolder(View view) {
        return MultIpleViewHolder.create(view);
    }

    @Override
    protected void convert(MultIpleViewHolder holder, MultipleItemEntity entity) {

        final String title;
        final String synopsis;
        final String text;
        final String imageUrl;
        final ArrayList<String> bannerImages;
        switch (holder.getItemViewType()){
            case ItemType.TITLE:
                title=entity.getField(MultipleFields.TITLE);
                synopsis="      "+entity.getField(MultipleFields.SYNOPSIS);
                holder.setText(R.id.text_title,title);
                holder.setText(R.id.text_synopsis,synopsis);
                break;
            case ItemType.BUTTON:
                text=entity.getField(MultipleFields.TEXT);
                imageUrl=entity.getField(MultipleFields.IMAGE_URL);
                Glide.with(mContext)
                        .load(imageUrl)
                        .diskCacheStrategy(DiskCacheStrategy.ALL)
                        .dontAnimate()
                        .centerCrop()
                        .into((ImageView) holder.getView(R.id.img_multiple));
                holder.setText(R.id.tv_multiple,text);
                break;
            case ItemType.BANNER:
                if(!mIsInitBanner){
                    bannerImages=entity.getField(MultipleFields.BANNERS);
                    final ConvenientBanner<String> convenientBanner=holder.getView(R.id.banner_recycler_item);
                    BannerCreator.setDefault(convenientBanner, bannerImages, new com.bigkoo.convenientbanner.listener.OnItemClickListener() {
                        @Override
                        public void onItemClick(int position) {
                            bannerPosition=position;
                        }
                    });
                    mIsInitBanner=true;
                }
                break;
            default:
                break;
        }
    }

    public static int getBannerPosition(){
       return  bannerPosition;
    }

    @Override
    public int getSpanSize(GridLayoutManager gridLayoutManager, int position) {
        return getData().get(position).getField(MultipleFields.SPAN_SIZE);
    }


    @Override
    public void onItemClick(int position) {

    }
}
4)、在需要使用适配器时,传入对应List数据,生成对应的适配器。
mAdapter=MultipleRecyclerAdapter.create(data);

3、Item Decoration 间隔样式

可以为item之间添加分割线。
任何分割线样式都需要自己实现

继承RecyclerView.ItemDecoration抽象类,并实现三个方法:
onDraw(Canvas c, RecyclerView parent, State state)
用于绘制间隔样式
onDrawOver(Canvas c, RecyclerView parent, State state)
用于绘制间隔样式
onDraw()和onDrawOver() 都是用于绘制间隔样式,只需要复写其中一个方法即可。

getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)
设置item的偏移量,偏移的部分用于填充间隔样式

也可以使用RecyclerView的分割线RecyclerView_Divider

4、Item Animator动画,

RecyclerView能够通过mRecyclerView.setItemAnimator(ItemAnimator animator)设置添加、删除、移动、改变的动画效果。
也可以直接使用默认动画DefaultItemAnimator,一般没特殊需求,使用默认动画即可。

三、Glide图片加载库

Item中图片的加载,使用Glide图片加载库。
只需引入依赖

//Glide
api 'com.github.bumptech.glide:glide:3.7.0'
api 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'

在需要加载图片的地方调用

String url = "http://xxx.jpg";
ImageView imageView = (ImageView) findViewById(R.id.imageView);
Glide.with(context)
    .load(url)
    .into(imageView);

使用Transformations可以对图片进行处理,包括圆角,灰阶等等。
这里需要对Item中的图片进行圆角的处理
示例代码:

public class RoundTransformation extends BitmapTransformation {
    private float radius = 0f;

    public RoundTransformation(Context context) {
        this(context, 4);
    }

    public RoundTransformation(Context context, int px) {
        super(context);
        this.radius = px;
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        LocalLogUtils.d("roundCrop",true);
        return roundCrop(pool, toTransform);
    }

    private Bitmap roundCrop(BitmapPool pool, Bitmap source) {
        LocalLogUtils.d("roundCrop",true);
        if (source == null)
            return null;

        LocalLogUtils.d("result",true);
        LocalLogUtils.d("source.getWidth()="+source.getWidth()+"    ,source.getHeight()="+source.getHeight(),true);
        Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
        canvas.drawRoundRect(rectF, radius, radius, paint);
        return result;
    }

    @Override
    public String getId() {
        return getClass().getName() + Math.round(radius);
    }
}

使用时调用 .transform() 方法,将自定义的 Transformation 的对象作为参数传递进去就可以了。
示例代码:

String url = "http://xxx.jpg";
ImageView imageView = (ImageView) findViewById(R.id.imageView);
Glide.with(context)
    .load(url)
    .transform(new RoundTransformation(context , 20))
    .into(imageView);

同时对图片进行圆角等处理,也可以使用第三方库Glide-transformations进行处理。

四、轮播图

轮播图使用ConvenientBanner图片轮播控件。ConvenientBanner支持无限循环,支持设置自动翻页和时间。
ConvenientBanner的使用
引入依赖

api 'com.bigkoo:convenientbanner:2.0.5'
api 'com.ToxicBakery.viewpager.transforms:view-pager-transforms:1.2.32@aar'

布局

<com.bigkoo.convenientbanner.ConvenientBanner
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/banner_recycler_item"
        android:layout_width="match_parent"
        android:layout_height="200dp"
/>

使用

    convenientBanner.setPages(new HolderCreator(),banner)
            .setPageIndicator(new int[]{R.drawable.dot_normal,R.drawable.dot_focus}) //设置两个点的图片作为翻页指示器
            .setPageIndicatorAlign(ConvenientBanner.PageIndicatorAlign.CENTER_HORIZONTAL) //设置指示器的方向
            .setOnItemClickListener(clickListener) //监听点击事件
            .setPageTransformer(new DefaultTransformer()) //设置翻页动画
            .startTurning(3000);//设置翻页时间间隔

图片加载也是使用Glide,并且对图片进行圆角处理

public class ImageHolder implements Holder<String> {
    private AppCompatImageView mImageView=null;
    @Override
    public View createView(Context context) {
        mImageView=new AppCompatImageView(context);
        return mImageView;
    }
    @Override
    public void UpdateUI(Context context, int position, String data) {

        Glide.with(context)
                .load(data)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .dontAnimate()
                .fitCenter()
                .transform(new RoundTransformation(context,10))
                .into(mImageView);
    }
}

五、数据整理

1、大概流程
从后台获取数据–>对数据进行整理–>填充进页面

2、从后台获取数据
后台数据要分页获取,每次获取一页的数据,并把页数存储起来。当上拉加载时 再获取下一页的数据。

上一篇:游戏社区App (四):底部导航栏
下一篇:游戏社区App (六):文章编辑与上传

你可能感兴趣的:(#,Android-APP)