• ViewPager使用记录1——展示固定数据


    ViewPager是v4支持库中的一个控件,相信几乎所有接触Android开发的人都对它不陌生。之所以还要在这里翻旧账,是因为我在最近的项目中有多个需求用到了它,觉得自己对它的认识不够深刻。我计划从最简单的使用场景出发,记录我到目前为止所对ViewPager的使用情况以及有关它的一些知识点。

    这个系列的代码将存放在Github仓库中,每篇文章对应一个分支。

    这是第一篇文章,讲述ViewPager最简单的使用场景,展示固定的数据。相关代码在分支:01-simple-usage可以获取。

    使用ViewPager展示固定的数据,首先要做的就是定义自己的PagerAdapter,在这个PagerAdapter里面封装数据的使用方法。然后通过ViewPager的setAdapter方法关联数据就完成了。

    定义PagerAdapter

    下面是我实现的PagerAdapter,用于在ViewPager中展示字符串列表:

    private static class UpdatePagerAdapter extends PagerAdapter {
    
        private List<String> texts;
    
        public UpdatePagerAdapter() {
            texts = new ArrayList<>();
        }
    
        @Override
        public int getCount() {
            return texts.size();
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view.equals(object);
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            String text = texts.get(position);
    
            TextView textView = new TextView(container.getContext());
            textView.setText(text);
    
            container.addView(textView);
            return textView;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    
        public void setTexts(List<String> texts) {
            this.texts.clear();
            if (texts != null && texts.size() > 0) {
                this.texts.addAll(texts);
            }
            notifyDataSetChanged();
        }
    }

    这个PagerAdapter主要实现了四个方法,分别是getCount、isViewFromObject、instantiateItem、destroyItem。这些都是PagerAdapter在ViewPager中需要被使用到的方法,其中getCount、isViewFromObject由于是抽象方法,因此被要求必须实现。

    看这四个方法的名称基本可以了解他们的作用。getCount方法用于告知ViewPager我们需要展示的数据的数目是多少;isViewFromObject用于告示ViewPager当前View是不是与第二个参数的object(问题1:这个方法的两个参数View和Object分别是做什么用的?)关联的;instantiateItem和destroyItem分别用户创建和销毁对象(问题2:为什么是xxxItem?类似ListView的适配器中getView的命名方式不是更贴切吗?例如instantiateView。)。

    关联ViewPager与PagerAdapter

    这个代码更简单了

    // 初始化数据列表 testDataSource1
    UpdatePagerAdapter adapter = new UpdatePagerAdapter();  
    adapter.setTexts(testDataSource1);
    
    ViewPager viewPager = (ViewPager) findViewById(R.id.vp_viewpager_update);  
    viewPager.setAdapter(adapter);  

    运行就可以看到你的数据展示在ViewPager里面了。

    PagerAdapter关键方法理解

    在实现PagerAdapter的时候我们留下了两个问题未解决。实际上这两个问题属于同源问题,是为了让数据与视图脱钩的解决方案。

    实际上instantiateItem和destroyItem之所以命名为Item是因为ViewPager在渲染的时候在其内部实现了一个名为InfoItem的对象列表来表示我们的数据。这个列表作为中间者把ViewPager的所有子View与我们提供的数据关联在一起。这样做可以让ViewPager用少量的View展示我们提供的可能有点多的数据,节约内存。

    以下是我自己画的ViewPager与PagerAdapter的关系图(原谅我不是专业设计师)

    ViewPager与PagerAdapter关系

    然而,数据是我们提供的,视图也是PagerAdapter委托我们自己实现的,ViewPager啥都不知道。因此怎么判断视图与其内部的item是否有关联的工作自然而然的也要委托给我们开发者来做。因此就有了isViewFromObject。

    另一种PagerAdapter实现方案

    接下来我将定义另一个PagerAdapter实现同样的功能。代码如下:

    private static class Update2PagerAdapter extends PagerAdapter {
    
        private List<String> texts;
    
        public Update2PagerAdapter() {
            texts = new ArrayList<>();
        }
    
        @Override
        public int getCount() {
            return texts.size();
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            String text = (String) view.getTag();
            return object.equals(text);
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            String text = texts.get(position);
    
            TextView textView = new TextView(container.getContext());
            textView.setTag(text);
            textView.setText(text);
    
            container.addView(textView);
            return text;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            View view = container.findViewWithTag(object);
            if (view != null) {
                container.removeView(view);
            }
        }
    
        public void setTexts(List<String> texts) {
            this.texts.clear();
            if (texts != null && texts.size() > 0) {
                this.texts.addAll(texts);
            }
            notifyDataSetChanged();
        }
    }

    主要的不同还在上述提到的三个方法实现。

    首先在instantiateItem中我在创建了TextView之后,调用了setTag方法给这个视图打个标签。这个标签的值就是我们的数据text,接着text作为方法的返回传递到ViewPager内部的InfoItem中保存起来。

    然后,当ViewPager需要判断数据和视图是否有关联的时候,调用isViewFromObject,传递出来View和Object。这个View就是上述的某个时候生成的TextView,Object就是返回的某个text。只要通过TextView的getTag方法读取标签,跟Object做一下对比就可以判断是否有关联。

    最后当视图需要被删除的时候,以Object作为标签参数,调用ViewPager的findViewWithTag找视图,如果视图存在就从ViewPager中移除。

    运行后发现效果跟前面的方案是一样的。

    本文来自作者同步博客

  • 相关阅读:
    Gitcafe绑定自定义域名
    如何优雅地使用Sublime Text
    使用Hexo搭建专属Blog
    How to Use Android ADB Command Line Tool
    雷军北大15分钟演讲:我至少有胆量去想(转)
    浅谈android中的目录结构
    react里 MD5加密
    git忽略相应文件夹,不上传
    antd-mobile的按需加载
    当react 项目使用px2rem
  • 原文地址:https://www.cnblogs.com/developerdaily/p/7683150.html
Copyright © 2020-2023  润新知