Android使用RecyclerView和StaggeredGridLayoutManager实现瀑布流效果-实现

版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/sinat_25074703/article/details/82981668
经过构建基础代码框架、创建StaggeredAdapter适配器、实现空界面效果之后,瀑布流的实现只是一个在StaggeredAdapter中添加ViewType类型的问题,这个类型就是FORMAL_ITEM对应正常的服务器数据,当然创建新的ViewHolder也是必须的。

7、实现StaggeredFormalViewHolder完成正常数据展示

7.1 创建StaggeredFormalViewHolder

万事开头难,先从简单的布局出发,这是只有一张商品图片和一个商品描述的简单展示,采用垂直线性布局,如下:

可见,只有一个ImageView和一个TextView垂直放置,在展示时通过保持图片宽高相等且占据去除填充的宽度的一半(因为只有2列,所以是一半),这样由于描述TextView字符串长短不同,就会造成包裹它的TextView的高度不一致,从而形成错落有致地效果,这就是我们想要的瀑布流。 在../src/main/res/layout上右击,选择New—>Layout resource file,在弹出的对话框的File name中输入布局文件名staggered_formal_item,Root element选项输入LinearLayout单击OK按钮,完成staggered_formal_item.xml的布局文件创建,如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_weight="1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/product_img"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_margin="5dp"
        android:layout_gravity="center_horizontal"
        android:scaleType="centerCrop"
        android:src="@drawable/staggered_formal_img"/>

    <TextView
        android:id="@+id/description_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:text="Formal Staggered Item"
        android:textSize="14sp"
        android:textColor="@android:color/holo_blue_dark"/>

</LinearLayout>

与创建StaggeredEmptyViewHolder一样,右击staggered包创建StaggeredFormalViewHolder,并加载staggered_formal_item.xml文件,代码如下:

package com.edwin.idea.staggered;

import android.content.Context;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import com.edwin.idea.R;

/**
 * Created by Edwin,CHEN on 2018/9/18.
 */

public class StaggeredFormalViewHolder extends RecyclerView.ViewHolder {

    private ImageView productImg;
    private TextView descriptionText;
    private Context mContext;

    public static StaggeredFormalViewHolder newInstance(ViewGroup viewGroup){
        View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.staggered_formal_item, viewGroup, false); // 注意:第三个参数是false,否则会异常,详见6.1节
        return new StaggeredFormalViewHolder(itemView);
    }

    private StaggeredFormalViewHolder(View itemView) {
        super(itemView);
        // 注意:mContext不要在newInstance方法里赋值,会造成内存泄漏。
        mContext = itemView.getContext();
        productImg = (ImageView) itemView.findViewById(R.id.product_img);
        int width = getScreenWidthPx();
        // 注意:每行布局有2列,以下两行代码的意思是,
        // 每个图片的宽度为w = width /2 - marginLeft - marginRight,marginLeft == marginRight == 5
        int margin = dip2px(mContext, 5 * 4);
        int w = (width - margin) / 2;
        ViewGroup.LayoutParams layoutParams = productImg.getLayoutParams();
        layoutParams.width = w;
        layoutParams.height = w;
        productImg.setLayoutParams(layoutParams);
        descriptionText = (TextView) itemView.findViewById(R.id.description_text);
    }

    private int getScreenWidthPx() {
        WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.widthPixels;
    }

    private int getScreenHeightPx() {
        WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.heightPixels;
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 sp 的单位 转成为 px(像素)
     */
    public static int sp2px(Context context, float spValue) {
        final float scale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

   /**
     * 在对itemView的childView添加点击监听时,可以将v.getContext()传入,因为从23.3.0开始它不再返回Activity,而是返回
     * TintContextWrapper
     * https://stackoverflow.com/questions/38814267/android-support-v7-widget-tintcontextwrapper-cannot-be-cast
     * @param context
     * @return
     */
    private Activity getActivity(Context context) {
        while (context instanceof ContextWrapper) {
            if (context instanceof Activity) {
                return (Activity)context;
            }
            context = ((ContextWrapper)context).getBaseContext();
        }
        return null;
    }
}

文件中的有几个工具方法是我们此次项目中用不到的,但是为了避免在工作中需要用到类似方法,一并添加到该文件中,方便随时使用。这里面还有一个大问题,就是图片显示使用的是ImageView,在我们的demo中这不会有什么问题,但是在实际的开发中,直接从服务器下载的图片是不可控的,大的可以达到上百兆,甚至几个G都是有可能的,这样必然引发OOM,当然一些第三方库已经帮我们解决了这个问题,后期再做介绍。

7.2创建model模型StaggeredVO,以适配服务器数据

StaggeredFormalViewHolder是为了展示服务器正常数据的,由于各个公司的服务器返回结构都是自定义的,其结构页千差万别,我们本章的目的是实现瀑布流效果,当然还有一个比较重要的原因是我也不擅长搭建服务器 ???。所以,这里直接模拟服务器最终返回结构,根据我们第一章提到的目标,我们最终至少要拿到3个元素:图片和文本描述,当然还有标签。他们对应三个字段,目前itemView未展示标签!在staggered文件夹下创建StaggeredVO.java文件,其代码如下:

package com.edwin.idea.staggered;

import java.io.Serializable;

/**
 * Created by Edwin,CHEN on 2018/9/18.
 */

public class StaggeredVO implements Serializable {
    private String price;
    private String description;
    private String imgUrl;

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getImgUrl() {
        return imgUrl;
    }

    public void setImgUrl(String imgUrl) {
        this.imgUrl = imgUrl;
    }
}

看到Serializable接口了吗,它是用来实现对象的序列化的,在开发中我们如果要使用Intent或Binder传递某个对象时,就必须对其进行序列号,否则会报异常。
有了钞票模板可以印钞,有了服务器数据模型就可以模拟数据,这个过程我们选择在StaggeredFragment.java文件中的initData中完成。

7.3模拟服务器数据

首先在StaggeredFragment.java文件中声明一个list泛型列表,如下:

    List<StaggeredVO> list;

StaggeredVO模板是List列表的泛型类型,保证创建的数据都是符合要求的,比如我们只要美元。然后在initData方法中模拟50条服务器数据,如下:

     @Override
     protected void initData() {
         list = new ArrayList<>();
         for (int i = 0; i < 50; i++) {
             StaggeredVO staggeredVO = new StaggeredVO();
             staggeredVO.setPrice("$ " + i); // 注意这里是有价格的,只是没显示
             if (i % 2 == 1) {
                 staggeredVO.setDescription("Staggered Formal Item " + i);
             }
             list.add(staggeredVO);
         }
    }

这样,服务器数据就模拟结束了,接下来完成数据的展示工作吧!

7.4完成正常数据展示,实现瀑布流效果

在本章开篇时提到,瀑布流的实现只是一个在StaggeredAdapter中添加新的ViewType类型的问题,这个新的类型和服务器数据模板StaggeredVO、StaggeredFormalViewHolder、每一条模拟数据时一一对应的。
首先,在StaggeredAdapter.java中创建静态常量FORMAL_ITEM对应StaggeredFormalViewHolder,代码如下:

private static final int FORMAL_ITEM = 1000;
private static final int EMPTY_ITEM = 1001;

当然,我们之前已经创建了一个空的ItemType类型,对应代码中的EMPTY_ITEM,那么如何区分这两个类型呢?
还是要从空的情况入手,通常有如下两个条件:

  1. list == null; 代码中没有对list 赋值,比如在StaggeredFragment文件中initData()是空实现
  2. list != null, 但是list.size() == 0;服务器什么都没返回

这样,我们区分开了这两个类型,就可以添加新的ViewType了。
还记得 6.2 节空数据展示时提到的RecyclerView.Adapter的4个方法的实现周期吗?如下图:

接着,我们就根据这四个方法的加载顺序来添加FORMAL_ITEM。
在StaggeredAdapter.java中声明list列表代表服务器数据,代码如下:

	private List<StaggeredVO> list = new ArrayList<>(50);

修改getItemCount()方法,将上面的1、2条件引入,代码如下:

    @Override
    public int getItemCount() {
        Log.d(TAG, "=====getItemCount");
        if (list == null || list.size() == 0) {
            // 空也要占一个item
            return 1;
        } else {
            return list.size();
        }
    }

修改getItemViewType方法,同样引入1、2条件,代码如下:

    @Override
    public int getItemViewType(int position) {
        Log.d(TAG, "===getItemViewType");
        if (list == null || list.size() == 0) {
            // 空也要占一个item
            return EMPTY_ITEM;
        } else {
            return FORMAL_ITEM;
        }
    }

注意,这里的position对应当前加载的1条服务器数据,对此你有什么想法吗?通过调用list.get(position)会有美妙的未来
修改onCreateViewHolder方法,代码如下:

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d(TAG, "======onCreateViewHolder");

        if (viewType == FORMAL_ITEM) {
            return StaggeredFormalViewHolder.newInstance(parent);
        }
        return StaggeredEmptyViewHolder.newInstance(parent);
    }

由于getItemViewType已经返回了不同的ViewType类型,这里就不必引入条件1、2了。如果再添加类型,只需要加else if条件返回对应ViewHolder就可以了,你想到这一层了吗?
修改onBindViewHolder,还记得它的作用吗?四个字:滑动更新。代码如下:

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        Log.d(TAG, "======onBindViewHolder");
        StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        if (list == null || list.size() == 0) {
            // 空也要占一个item
            layoutParams.setFullSpan(true);            ((StaggeredEmptyViewHolder)holder).itemView.setLayoutParams(layoutParams);
        } else {
            layoutParams.setFullSpan(false);
            ((StaggeredFormalViewHolder)holder).onBind(list.get(position));
        }
    }

最后一行代码报异常了,原因是我们并未在StaggeredFormalViewHolder创建onBind()方法。这里有两点需要注意:

  1. position对应的是当前某条服务器数据
  2. onBindViewHolder更新的是整个itemView的UI
    基于以上两点,我们需要将整条数据传给StaggeredFormalViewHolder,每一条数据对应一个StaggeredVO实例,那么在StaggeredFormalViewHolder.java文件中添加onBind(StaggeredVO vo)方法如下:

    /**
     * 刷新itemView并对其子view填充数据
     * @param vo
     */
    public void onBind(StaggeredVO vo) {
        if (!TextUtils.isEmpty(vo.getImgUrl())) {
            productImg.setImageURI(Uri.parse(vo.getImgUrl()));
        }
        if (!TextUtils.isEmpty(vo.getDescription())) {
            descriptionText.setText(vo.getDescription());
            descriptionText.setVisibility(View.VISIBLE);
        } else {
            descriptionText.setVisibility(View.GONE);
        }
    }

StaggeredFormalViewHolder.java的代码如下:

package com.edwin.idea.staggered;

import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import com.edwin.idea.R;

/**
 * Created by Edwin,CHEN on 2018/9/18.
 */

public class StaggeredFormalViewHolder extends RecyclerView.ViewHolder {

    private ImageView productImg;
    private TextView descriptionText;
    private Context mContext;

    public static StaggeredFormalViewHolder newInstance(ViewGroup viewGroup){
        View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.staggered_formal_item, viewGroup, false);
        return new StaggeredFormalViewHolder(itemView);
    }

    private StaggeredFormalViewHolder(View itemView) {
        super(itemView);
        mContext = itemView.getContext();
        productImg = (ImageView) itemView.findViewById(R.id.product_img);
        int width = getScreenWidthPx();
        int margin = dip2px(mContext, 5 * 4);
        int w = (width - margin) / 2;
        ViewGroup.LayoutParams layoutParams = productImg.getLayoutParams();
        layoutParams.width = w;
        layoutParams.height = w;
        productImg.setLayoutParams(layoutParams);
        descriptionText = (TextView) itemView.findViewById(R.id.description_text);
    }

    /**
     * 刷新itemView并对其子view填充数据
     * @param vo
     */
    public void onBind(StaggeredVO vo) {
        if (!TextUtils.isEmpty(vo.getImgUrl())) {
            productImg.setImageURI(Uri.parse(vo.getImgUrl()));
        }
        if (!TextUtils.isEmpty(vo.getDescription())) {
            descriptionText.setText(vo.getDescription());
            descriptionText.setVisibility(View.VISIBLE);
        } else {
            descriptionText.setVisibility(View.GONE);
        }
    }

    private int getScreenWidthPx() {
        WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.widthPixels;
    }

    private int getScreenHeightPx() {
        WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.heightPixels;
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 sp 的单位 转成为 px(像素)
     */
    public static int sp2px(Context context, float spValue) {
        final float scale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    /**
     * 在对itemView的childView添加点击监听时,可以将v.getContext()传入,因为从23.3.0开始它不再返回Activity,而是返回
     * TintContextWrapper
     * https://stackoverflow.com/questions/38814267/android-support-v7-widget-tintcontextwrapper-cannot-be-cast
     * @param context
     * @return
     */
    private Activity getActivity(Context context) {
        while (context instanceof ContextWrapper) {
            if (context instanceof Activity) {
                return (Activity)context;
            }
            context = ((ContextWrapper)context).getBaseContext();
        }
        return null;
    }
}

修改了以上4个方法解决了异常之后,我们只需要将服务器模拟数据list设置给adapter的list就可以完成数据展示了。这是多么大的一个难题啊,我突然间不知道怎么完成了,你会吗?
好像是在StaggeredAdapter类中添加一个setData方法,然后在StaggeredFragment中调用它就好了。
在StaggeredAdapter类中,选中list字段Command + N(或者右键鼠标,点击Generate),在弹出的GenerateMenu列表中选中Setter选项,产生setList方法,将setList改成setData即可。

	private List<StaggeredVO> list = new ArrayList<>(50);
	    
	/**
     * 将服务器数据设置给Adapter
     * @param list
     */
	public void setData(List<StaggeredVO> list) {
        this.list = list;
    }

修改StaggeredFormalViewHolder.java后的代码如下:

package com.edwin.idea.staggered;

import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Edwin,CHEN on 2018/9/18.
 */

public class StaggeredAdapter extends RecyclerView.Adapter {

    private static final String TAG = StaggeredAdapter.class.getSimpleName();

    private static final int FORMAL_ITEM = 1000;
    private static final int EMPTY_ITEM = 1001;

    private List<StaggeredVO> list = new ArrayList<>(50);

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d(TAG, "======onCreateViewHolder");

        if (viewType == FORMAL_ITEM) {
            return StaggeredFormalViewHolder.newInstance(parent);
        }
        return StaggeredEmptyViewHolder.newInstance(parent);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        Log.d(TAG, "======onBindViewHolder");
        StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        if (list == null || list.size() == 0) {
            // 空也要占一个item
            layoutParams.setFullSpan(true);
            ((StaggeredEmptyViewHolder)holder).itemView.setLayoutParams(layoutParams);
        } else {
            layoutParams.setFullSpan(false);
            // 这里的itemView是RecyclerView.ViewHolder的final public字段,可以直接使用
            // 它就是StaggeredFormalViewHolder对应布局文件staggered_formal_item.xml的LinearLayout
            ((StaggeredFormalViewHolder) holder).itemView.setSelected(position == selectedIndex);
            ((StaggeredFormalViewHolder)holder).onBind(list.get(position));
       }
    }

    @Override
    public int getItemCount() {
        Log.d(TAG, "=====getItemCount");
        if (list == null || list.size() == 0) {
            // 空也要占一个item
            return 1;
        } else {
            return list.size();
        }
    }

    @Override
    public int getItemViewType(int position) {
        Log.d(TAG, "===getItemViewType");
        if (list == null || list.size() == 0) {
            // 空也要占一个item
            return EMPTY_ITEM;
        } else {
            return FORMAL_ITEM;
        }
    }

    /**
     * 将服务器数据设置给Adapter
     * @param list
     */
    public void setData(List<StaggeredVO> list) {
        this.list = list;
    }
}

最后,在StaggeredFragment.java的onCreate()方法中调用setData(list)将服务器数据设置给StaggeredAdapter代码如下:

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        viewGroupRoot = (ViewGroup) inflater.inflate(R.layout.fragment_staggered, null);

        recyclerView = (RecyclerView) viewGroupRoot.findViewById(R.id.recycler_view);
        staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        staggeredAdapter = new StaggeredAdapter();
        initData();//别忘了调用initData()模拟服务器数据,实际中是从服务器拿来的
        staggeredAdapter.setData(list);
        recyclerView.setLayoutManager(staggeredGridLayoutManager);
        recyclerView.setAdapter(staggeredAdapter);

        return viewGroupRoot;
    }

注意:别忘了调用initData()模拟服务器数据,否则显示的是空页面
StaggeredFragment.java代码如下:

package com.edwin.idea.staggered;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.edwin.idea.AbstractFragment;
import com.edwin.idea.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Edwin,CHEN on 2018/9/18.
 */

public class StaggeredFragment extends AbstractFragment {

    ViewGroup viewGroupRoot;
    RecyclerView recyclerView;
    StaggeredGridLayoutManager staggeredGridLayoutManager;
    StaggeredAdapter staggeredAdapter;

    List<StaggeredVO> list;

    public static Fragment newInstance(){
        return new StaggeredFragment();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        viewGroupRoot = (ViewGroup) inflater.inflate(R.layout.fragment_staggered, null);

        recyclerView = (RecyclerView) viewGroupRoot.findViewById(R.id.recycler_view);
        staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        staggeredAdapter = new StaggeredAdapter();
        initData();
        staggeredAdapter.setData(list);
        recyclerView.setLayoutManager(staggeredGridLayoutManager);
        recyclerView.setAdapter(staggeredAdapter);

        return viewGroupRoot;
    }

     @Override
     protected void initData() {
         list = new ArrayList<>();
         for (int i = 0; i < 50; i++) {
             StaggeredVO staggeredVO = new StaggeredVO();
             staggeredVO.setPrice("$ " + i);
             if (i % 2 == 1) {
                 staggeredVO.setDescription("Staggered Formal Item " + i);
             }
             list.add(staggeredVO);
         }
    }
}

好了,Ctrl + R运行一下吧,下图应该就是你心心念的瀑布流效果了~

介意我我说一句吗?这效果不理想呢~

7.6 添加点击事件

对于事件开发中,每一个itemView的点击事件是必不可少的,其实实现起来相当简单。只需要在onBindViewHolder中对itemView添加OnClickListener监听事件,代码如下:

            ((StaggeredFormalViewHolder) holder).itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(v.getContext(), "position" + position, Toast.LENGTH_SHORT).show();
                }
            });

7.7 添加选中事件

有事为了凸显当前选中的itemView,做一些颜色上的特殊展示也是必须的,这个主要通过itemView.setSelected()方法来完成,该方法会触发view的invalidate完成重绘,更改后onBindViewHolder代码如下:

    private int selectedIndex; // 添加当前被选中index

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        Log.d(TAG, "======onBindViewHolder");
        StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        if (list == null || list.size() == 0) {
            // 空也要占一个item
            layoutParams.setFullSpan(true);
            ((StaggeredEmptyViewHolder) holder).itemView.setSelected(position == selectedIndex);
            ((StaggeredEmptyViewHolder)holder).itemView.setLayoutParams(layoutParams);
        } else {
            layoutParams.setFullSpan(false);
            ((StaggeredFormalViewHolder) holder).itemView.setSelected(position == selectedIndex);
            ((StaggeredFormalViewHolder)holder).onBind(list.get(position));
            ((StaggeredFormalViewHolder) holder).itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (selectedIndex != position) {
                        selectedIndex = position;
                    }
                    Toast.makeText(v.getContext(), "position = " + position, Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

可以通过更改itemView的背景色来完成验证哦~
有诗云:

醉里挑灯看剑,梦回吹角连营。八百里分麾下炙,五十弦翻塞外声。沙场秋点兵。
马作的卢飞快,弓如霹雳弦惊。了却君王天下事,赢得生前身后名。可怜白发生!
以下是使用Kotlin语言实现瀑布流效果的示例代码: 1. 在build.gradle文件中添加以下依赖: ``` implementation 'com.android.support:recyclerview-v7:28.0.0' ``` 2. 创建一个RecyclerView,在XML布局文件中添加以下代码: ``` <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutManager="android.support.v7.widget.StaggeredGridLayoutManager" app:spanCount="2" app:gapStrategy="balanced" android:padding="8dp"/> ``` 3. 创建一个Adapter类,继承RecyclerView.Adapter,并实现以下方法: ``` class CustomAdapter(private val dataList: List<String>) : RecyclerView.Adapter<CustomViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false) return CustomViewHolder(view) } override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { holder.bind(dataList[position]) } override fun getItemCount(): Int { return dataList.size } } ``` 4. 创建一个ViewHolder类,继承RecyclerView.ViewHolder,并实现以下方法: ``` class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { fun bind(item: String) { val textView = itemView.findViewById<TextView>(R.id.itemText) textView.text = item } } ``` 5. 在Activity或Fragment中,设置RecyclerView的Adapter和LayoutManager,并传入数据进行显示: ``` val dataList = listOf( "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9", "Item 10" ) recyclerView.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) recyclerView.adapter = CustomAdapter(dataList) ``` 这样,就可以在RecyclerView实现瀑布流效果了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值