android recyclerview使用glide以瀑布流显示,并绑定菜单

本文介绍了如何在Android中使用RecyclerView替代GridView,并实现瀑布流显示。通过StaggeredGridLayoutManager实现瀑布流布局,利用Glide 4.x加载图片。详细讲解了RecyclerView的滑动刷新数据、添加点击事件以及结合菜单的操作,包括滑动监听、菜单注册与事件处理的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

RecyclerView是Google建议使用用于替换GridView,ListView等控件的新控件,这里主要记录在替换过程中所遇到的一些问题, 以及它们的解决办法。

如何定义RecyclerView

RecyclerView相比于GridView等控件,比较大的区别有:
1、默认使用ViewHolder进行View的重用。
2、使用LayoutManager进行布局的控制,更加灵活。
在使用时,需要分别定义并设置:

RecyclerView recyclerView = findViewById(R.id.content_grid_view);
mRecyclerViewAdapter = new RecyclerViewAdapter(MainPage.this);
recyclerView.setAdapter(mRecyclerViewAdapter);
int column = getResources().getInteger(R.integer.grid_columns);
final StaggeredGridLayoutManager layoutManager = 
	new StaggeredGridLayoutManager(column, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);

其中StaggeredGridLayoutManager是原生提供的瀑布流布局,只需要指定列数及方向即可。
注意到这里绑定了我们自定义的RecyclerViewAdapter,其实现如下:

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {
    private Context mAdapterContext;

    private RecyclerViewAdapter(Context context) {
        mAdapterContext = context;
    }

    @Override
    public @NonNull RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mAdapterContext).inflate(R.layout.grid_item, parent, false);
        return new RecyclerViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerViewHolder viewHolder, int position) {
        HashMap<String, String> map = mList.get(position);
        if (map == null) {
            Log.d(TAG, "map is null");
            return;
        }
        String imageData = map.get(IMAGE_KEY);
        String textData = map.get(TEXT_KEY);

        Util.setPicFromUrl(MainPage.this, imageData, viewHolder.imageView);
        viewHolder.textView.setText(textData);

        setOnClickListener(viewHolder, position);
        setMenuListener(viewHolder, position);
    }

    ......

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

    class RecyclerViewHolder extends RecyclerView.ViewHolder {
        private View itemView;
        private ImageView imageView;
        private TextView textView;

        RecyclerViewHolder(View view) {
            super(view);
            itemView = view;
            imageView = view.findViewById(R.id.image_item);
            textView = view.findViewById(R.id.text_item);
        }
    }
}

可以看到对应的ViewHolder的定义,及其在onBindViewHolder方法中是如何使用的。

使用Glide

在对GridView进行替换时,也将Glide从3.x升级到了4.x版本。使用方法有些许变化:
1、默认的loading图片从直接设置改为通过option传递

RequestOptions options = new RequestOptions().placeholder(R.drawable.ic_loading);
Glide.with(context).load(url).apply(options).into(imageView);

2、下载图片时参数类型发生了变化

Glide.with(viewPage).asBitmap().load(url).into(new SimpleTarget<Bitmap>() {
    @Override
    public void onResourceReady(@NonNull Bitmap bitmap, Transition<? super Bitmap> transition) {
        ......
    }
});

滑动刷新数据

在GridView或者ListView时,如果要实现滑动到底部加载更多数据,一般会通过对View榜定滑动方法实现,比如:

mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (view.getLastVisiblePosition() == view.getCount() - 1) {
            updateImage();
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }
});

但是在修改时发现存在问题,RecyclerView在使用瀑布流的情况下,并没有所谓的最后一个对象,取而代之的是LayoutManager中,获取最后一组对象的方法:

final StaggeredGridLayoutManager layoutManager = 
	new StaggeredGridLayoutManager(column, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
layoutManager.findLastVisibleItemPositions(null);

可见过去的判断方法不能继续使用,我们可以考虑对滑动行为进行判断:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
        if (!recyclerView.canScrollVertically(-1)) {
            mWebOperation.updatePage();
        }
    }
});

这里-1表示向下滑动(1表示向上滑动),从而触发滑动到底部时的行为。

增加click事件

Google没有为RecyclerView提供默认的click事件,这可能是由于RecyclerView将Layout交给用户自行控制,此时View是可以重叠的,没办法给出默认的行为?
因此,我们没有办法直接在RecyclerView整体绑定click事件,经过查阅资料,此时比较好的方法是在onBindViewHolder时,对于单个的View进行事件的处理:

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {
    ......

    @Override
    public void onBindViewHolder(@NonNull RecyclerViewHolder viewHolder, int position) {
        ......

        setOnClickListener(viewHolder, position);
        ......
    }

    private void setOnClickListener(RecyclerViewHolder viewHolder, final int pos) {
        viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ......
            }
        });
    }

    ......
}

通过对整个itemView设置clickListener,实现监听click的行为。

增加menu及menu事件

注册menu,对于GridView或者ListVIew,其中一种写法是:

registerForContextMenu(mListView);

对于对应的控件注册菜单

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    if (v.getId() == R.id.content_list_view) {
        getMenuInflater().inflate(R.menu.viewpage_menu, menu);
    }
}

重写Activity的onCreateContextMenu方法,通过判断触发事件的控件,决定是否需要绘制菜单。

@Override
public boolean onContextItemSelected(MenuItem item) {
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
    int menuItemIndex = item.getItemId();
    Log.d(TAG, "menuItem is " + menuItemIndex);
    ......
    return true;
}

重写Activity的onContextItemSelected方法,如果处理的菜单是ListView或者GridView的,从AdapterView.AdapterContextMenuInfo中获取哪个菜单选项被选中。
在切换到RecyclerView后,下面两条都不再生效,这是因为:
1、Google没有为RecyclerView提供默认的menu事件
2、触发menu后也不再有AdapterView.AdapterContextMenuInfo可用
变通的方法和click时类似,仍然通过在itemView绑定时设置:

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {
    ......

    @Override
    public void onBindViewHolder(@NonNull RecyclerViewHolder viewHolder, int position) {
        ......

        setMenuListener(viewHolder, position);
    }

    ......

    private void setMenuListener(RecyclerViewHolder viewHolder, final int pos) {
        viewHolder.itemView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
            @Override
            public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
                ......
                getMenuInflater().inflate(R.menu.mainpage_menu, menu);
                for (int index = 0; index < menu.size(); index++) {
                    MenuItem item = menu.getItem(index);
                    if (item.getItemId() == R.id.mainpage_delete_set) {
                        item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                            @Override
                            public boolean onMenuItemClick(MenuItem item) {
                                ......
                                return false;
                            }
                        });
                    }
                }
            }
        });
    }

    ......
}

这样就可以正确弹出菜单,并获取具体点击了菜单的哪个选项。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值