Android中HorizontalScrollView用BaseAdapter实现横向画廊的适配问题
答题应用卡片画廊实现问题
需求背景
我是初级开发者,正在开发附带收藏品奖励功能的答题应用:用户完成答题后可获得英雄卡片作为奖励,收集到的卡片可在专属画廊页面查看。目前画廊功能实现遇到阻碍:
官方原生Gallery控件已停止支持,我计划使用标准HorizontalScrollView实现,预期布局效果如下:
页面底部为滚动区域,卡片横向排列,支持左右滑动浏览;点击任意卡片后,卡片会在上方ImageView(简称IV)中展示,旁侧TextView(简称TV)用于展示卡片相关信息,该部分本次暂不涉及。
遇到的问题
HorizontalScrollView没有setAdapter方法,无法直接通过BaseAdapter填充图片资源。我知道ListView、GridView可以绑定适配器实现列表效果,但需要的是横向滚动的画廊样式。
我也尝试过使用ViewPager实现该效果,但同样出现问题:自定义继承BaseAdapter的适配器无法直接设置给ViewPager,调用viewPager.setAdapter(cardGalleryAdapter);时提示需要对应类型的适配器,而非自定义的BaseAdapter子类。另外我是在Fragment而非Activity中实现该功能,不确定是否是该原因导致报错。
现有实现代码
适配器类代码
public class CardGalleryAdapter extends BaseAdapter { private Context context; private int [] cards; public CardGalleryAdapter(Context c, int [] images){ context = c; this.cards = images; } @Override public int getCount() { return cards.length; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView = new ImageView(context); imageView.setImageResource(cards[position]); imageView.setLayoutParams(new ViewGroup.LayoutParams(200, 200)); return imageView; } }
Fragment类代码
public class DeckFragment extends Fragment implements View.OnClickListener { HorizontalScrollView gallery; ImageView cardView; TextView cardText; CardGalleryAdapter cardGalleryAdapter; DeckCards deckCards; ViewPager2 viewPager; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // 初始化控件对象 View view = inflater.inflate(R.layout.fragment_deck, container, false); // 尝试用HorizontalScrollView实现画廊未成功 gallery.findViewById(R.id.gallery); gallery.setOnClickListener(this); cardView.findViewById(R.id.cardView); cardText.findViewById(R.id.cardText); viewPager.findViewById(R.id.viewPager); // 单独类,存储卡片数组资源 deckCards = new DeckCards(); cardGalleryAdapter = new CardGalleryAdapter(getContext(), deckCards.getCards()); // 尝试用ViewPager替代HorizontalScrollView,出现前述类型不匹配报错 viewPager.setAdapter(cardGalleryAdapter); return view; } @Override public void onClick(View v) { } }
问题原因与解决方法
报错和在Fragment中实现功能没有任何关系,核心问题有两点:
- 不同控件的适配器类型不通用:
BaseAdapter是为AbsListView系列控件(ListView、GridView、已废弃的原生Gallery)设计的,HorizontalScrollView、ViewPager、ViewPager2、RecyclerView都有各自专属的适配器规范,不能直接传入BaseAdapter子类。 - 现有控件初始化写法存在空指针风险:
findViewById需要调用inflate得到的根View对象的方法,正确写法应为gallery = view.findViewById(R.id.gallery),直接调用控件自身的findViewById没有给控件实例赋值,运行时会直接崩溃。
两种可落地的实现方案:
- 方案一:使用ViewPager2实现(推荐)
你代码中已经声明了ViewPager2控件,它是官方目前推荐的横向滑动实现组件,底层基于RecyclerView,自带视图复用机制性能更好,还可以很方便地实现卡片居中、选中放大、滑动对齐等画廊效果。只需要把自定义适配器改为继承RecyclerView.Adapter,实现对应ViewHolder创建、数据绑定的逻辑即可,不需要自己处理滑动和视图缓存。 - 方案二:使用HorizontalScrollView实现
HorizontalScrollView本身只是个滚动容器,没有适配器绑定能力,需要在它内部嵌套一个orientation设置为horizontal的LinearLayout作为卡片容器,手动遍历卡片资源数组,逐个创建ImageView实例添加到LinearLayout中。这种方式没有视图复用,卡片数量较多时会出现卡顿,仅适合卡片数量极少的场景。
内容的提问来源于stack exchange,提问作者Sandman
相关产品推荐
相关产品推荐

