photo player 显示☞列表选中项的处理

一、需求

  1. 需要显示一个图片列表,可以左右滑动,点击则在大图显示该图;
  2. 可以在界面上显示大图,可以左右滑动切换图片,可以支持zoom、move、rotate;
  3. 大图与图片列表相互关联:
    • 点击列表item可以在show对应大图;
    • 大图切换则列表保持该Item在列表中间位置;
    • 对于大图显示的图片添加红框标记(item的两个背景);

效果如此图:

二、当前方案

  1. 大图显示使用ViewPager控件实现,则可以支持左右滑动切换图片功能(支持预加载);
  2. 图片列表使用RecyclerView控件来实现,则可以支持列表功能,同时其缓存机制对于机器更加友好;
  3. 列表关联功能可以自行实现:
    • 点击item show对应大图:对每个item添加点击事件监听,点击则设置viewpager显示指定position图片;
    • 添加对于ViewPager的滑动监听,添加对于列表移动的处理;
    • 显示的图片在列表中设置红框标记,这里前后使用两个方案实现:
      1. 使用arraylist维护对应的标记,在show图片时添加判断,viewpager切换则刷新列表显示;
      2. 在adapter中维护一个变量,记录当前显示的图片,viewpager切换则刷新列表中背景切换的两个item,且仅处理其背景,并不刷新该item中imageview;

本次记录的重点在于红框标记的两个方案实现,方案2比方案1节省了大量资源:列表、刷新item数量、控件

三、关联具体实现

3.1 方案一:

  1. adapter中维护一个boolean类型的list,大小与imagelist相同,选中设置为true,其余设置为false:

    public List<Boolean> isClicks;
    //控件是否被点击,默认为false,如果被点击,改变值,控件根据值改变自身颜色
    isClicks = new ArrayList<>();
    for (int i = 0; i < mImageList.size(); i++) {isClicks.add(false);
    }
    
  2. 在init list item view的时候,判断上述值:

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {...if (isClicks.get(position)) {imageItem.setBackgroundResource(R.drawable.photo_preview__btn_p);} else {imageItem.setBackgroundResource(R.drawable.photo_preview__btn_n);}...
    }
    
  3. ViewPager滑动的时候改变对应的值,并更新:

    private NoPreloadViewPager.OnPageChangeListener mPhotoPageChangeListener = new NoPreloadViewPager.OnPageChangeListener() {@Overridepublic void onPageSelected(int position) {mPosition = position;mRecycleAdapter.isClicks.set(mPosition, true);for(int i = 0; i <mRecycleAdapter.isClicks.size();i++){mRecycleAdapter.isClicks.set(i,false);}mRecycleAdapter.isClicks.set(position,true);//此接口会将所有可见的item重新刷新一遍mRecycleAdapter.notifyDataSetChanged();MoveToPosition(mLayoutManager, mPhotoListView, position);}@Overridepublic void onPageScrolled(int arg0, float arg1, int arg2) {}@Overridepublic void onPageScrollStateChanged(int arg0) {//arg0 ==1的时表示正在滑动,arg0==2的时表示滑动完毕了,arg0==0的时表示什么都没做。if (arg0 == 0) {} else if (arg0 == 1) {} else if (arg0 == 2) {}}
    };//根据当前view切换将要显示的item移动到中间位置
    public void MoveToPosition(LinearLayoutManager manager, RecyclerView recyclerView, int position) {int firstItem = manager.findFirstVisibleItemPosition();int lastItem = manager.findLastVisibleItemPosition();int offset = (lastItem - firstItem) / 2;int maxItem = mPhotoList.size() - 1;int center = (lastItem + firstItem) / 2;int offsetPosition = 0;if (position < center) {offsetPosition = position - offset;} else if (position == center) {offsetPosition = position;} else {offsetPosition = position + offset;}if (offsetPosition < 0) {offsetPosition = 0;} else if (offsetPosition > maxItem) {offsetPosition = maxItem;}recyclerView.scrollToPosition(offsetPosition);
    }
    
  4. 列表item点击时:

    private PhotoListAdapter.Callback mPhotoListItemCallback = new PhotoListAdapter.Callback() {@Overridepublic void onItemClick(Image image, ImageView imageItem) {mPosition = mPhotoList.indexOf(image);//todo set the current item in centermPhotoView.setCurrentItem(mPosition);}
    };
    

    这里在点击列表item的时候并没有做notify item列表的处理:1. 这里两个控件要避免操作成环;
    2. ViewPager控件中的setCurrentItem接口,在其内部实现中会调用到:mOnPageChangeListener.onPageSelected(item);

    /*** Set the currently selected page. If the ViewPager has already been through its first* layout there will be a smooth animated transition between the current item and the* specified item.* @param item Item index to select*/
    public void setCurrentItem(int item) {mPopulatePending = false;setCurrentItemInternal(item, !mFirstLayout, false);
    }/*** Set the currently selected page.* @param item Item index to select* @param smoothScroll True to smoothly scroll to the new item, false to transition immediately*/
    public void setCurrentItem(int item, boolean smoothScroll) {mPopulatePending = false;setCurrentItemInternal(item, smoothScroll, false);
    }
    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {setCurrentItemInternal(item, smoothScroll, always, 0);
    }void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {if (mAdapter == null || mAdapter.getCount() <= 0) {setScrollingCacheEnabled(false);return;}if (!always && mCurItem == item && mItems.size() != 0) {setScrollingCacheEnabled(false);return;}if (item < 0) {item = 0;} else if (item >= mAdapter.getCount()) {item = mAdapter.getCount() - 1;}final int pageLimit = mOffscreenPageLimit;if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {// We are doing a jump by more than one page.  To avoid// glitches, we want to keep all current pages in the view// until the scroll ends.for (int i=0; i<mItems.size(); i++) {mItems.get(i).scrolling = true;}}final boolean dispatchSelected = mCurItem != item;mCurItem = item;populate();final int destX = (getWidth() + mPageMargin) * item;if (smoothScroll) {smoothScrollTo(destX, 0, velocity);if (dispatchSelected && mOnPageChangeListener != null) {mOnPageChangeListener.onPageSelected(item);}} else {if (dispatchSelected && mOnPageChangeListener != null) {mOnPageChangeListener.onPageSelected(item);}completeScroll();scrollTo(destX, 0);}
    }
    

    所以这里按照上述方式实现:

    1. 维护一个list;
    2. 每次更新都在重新设置一遍list;
    3. notify 数据变化时,当前可见的item都要刷新一遍;

3.2 方案二:

基于上述方案进行优化:

  1. 由于每次选中的图片仅一个,则可以使用一个变量来维护;
  2. 每次在view切换的时候,现在是更新整个list,而这里可以仅设置一个值;
  3. 每次在view切换之后需要通知列表更新数据,现在是更新所有可见列表,这里可以仅更新两个item;
  4. 每次更新view的时候,都是将这个view完整的重新加载,这里可以仅更新item的背景图,而不去重新加载图片;

则具体来看code实现:

  1. 使用变量来标记当前显示的图片:

    //M: add select solution
    private int selectPosition = -1;
    public void setSelectPosition(int position) {if (0 > position ||mImageList.size() < position ){Debug.i(TAG, "position error: " + position);return;}selectPosition = position;
    }
    public int getSelectPosition( ) {return selectPosition;
    }
    
  2. 获取此前一次显示的位置,更新当前显示的位置,并通知adapter有数据变化::

    //add viewpager item click listener
    private NoPreloadViewPager.OnPageChangeListener mPhotoPageChangeListener = new NoPreloadViewPager.OnPageChangeListener() {int oldPosition = 0;@Overridepublic void onPageSelected(int position) {mPosition = position;//获取前一个显示的position,并设置当前显示的position;oldPosition = mRecycleAdapter.getSelectPosition();mRecycleAdapter.setSelectPosition(position);//注意,这里更新使用notifyItemChanged,仅更新上述两个位置的item//第二个参数为0表示payloads不为空,是只更新item某一个控件,而不是完整更新的关键mRecycleAdapter.notifyItemChanged(oldPosition, 0);mRecycleAdapter.notifyItemChanged(position, 0);//照例让RecyclerView滑动到指定位置MoveToPosition(mLayoutManager, mPhotoListView, position);}@Overridepublic void onPageScrolled(int position, float arg1, int arg2) {}@Overridepublic void onPageScrollStateChanged(int arg0) {//arg0 ==1的时表示正在滑动,arg0==2的时表示滑动完毕了,arg0==0的时表示什么都没做。if (arg0 == 0) {} else if (arg0 == 1) {} else if (arg0 == 2) {}}
    };
    
  3. adapter中处理仅更新item的背景图:

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
    }//此函数不去实现,转而实现下述带payloads参数的接口@Override
    public void onBindViewHolder(final ViewHolder holder, final int position, List payloads) {final Image image = mImageList.get(position);final ImageView imageItem = holder.imageItem;final ProgressBar loading = holder.loading;final String imagePath = image.getImagePath();if(payloads.isEmpty()) {//这里是关键:正常刷新时走这里,主要是load图片和添加click监听imageItem.setImageDrawable(mContext.getDrawable(R.drawable.photo_preview__btn_n));loading.setVisibility(View.VISIBLE);holder.imageItem.setTag(imagePath);mImageLoader.loadImage(holder.imageItem,imagePath,true,position,new ImageLoader.onImageLoadedListener() {@Overridepublic void displayImage(ImageView view, Bitmap bitmap) {//check if there is the correct viewString path = view.getTag().toString();if (path.equals(imagePath)) {view.setImageBitmap(bitmap);loading.setVisibility(View.GONE);}}});if (mCallback != null) {holder.imageItem.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mCallback.onItemClick(position, imageItem);}});}} else {//选中图片背景图更新时走这里,只判断position更新背景图//set background resource//init or select all need set the background rescource, so move it // to this function out}if (position == selectPosition) {imageItem.setBackgroundResource(R.drawable.photo_preview__btn_p);} else {imageItem.setBackgroundResource(R.drawable.photo_preview__btn_n);}
    }
    

    整体来讲改动比较小,但是加载图片时对于资源的消耗要降低了很多

photo player 显示 ☞ 列表选中项的处理相关推荐

  1. Flash Player渲染模型(显示列表)

    显示列表是Flash Player 9以后才有的Flash渲染模型,这是一个非常重要的模型.那么为什么要彻底改变Flash对图形的操作方式呢?原因有两个:速度和简化.以前显示列表各个方面都是Movie ...

  2. ListBox选中项数量显示于TextBox文本框中

    要完成的功能:点击ListBox选中一个或多个选项时,TextBox中自动显示选中项的数量. 如下图显示: 分析: 你原先错误的思路:ListBox配置好数据源,然后在TextBox的后台事件Text ...

  3. ASP.NET MVC中为DropDownListFor设置选中项的方法

    在MVC中,当涉及到强类型编辑页,如果有select元素,需要根据当前Model的某个属性值,让Select的某项选中.本篇只整理思路,不涉及完整代码. □ 思路 往前台视图传的类型是List< ...

  4. vue 中使用element-ui的menu选中项高亮的问题

    在使用element中的menu组件时,根据官方文档,可以设置给el-menu设置router属性为:true,给el-menu-item设置index的值为路径,就可以实现点击导航跳转到指定路由. ...

  5. Android ListView选中项居中放大(使用上下键控制,非触屏)

    最近有一个功能机项目(不支持触屏)需要实现ListView选中项停在中间放大的效果,网络上的大多是用手滑动屏幕的效果,只能自己写一个. 效果实现了,但是还有小问题.实现原理主要是 1调用setSele ...

  6. sharepoint中显示网页库item的webpart和显示列表库item的webpart

    首先是在任意位置显示网页库中网页的ITEM的webpart 公司动态和公司公告列表Page在只显示Title的情况先查询出来的栏 Title _ModerationStatus(审批状态) ID Fi ...

  7. Qt5 QML TreeView currentIndex当前选中项的一些问题

    0.前言 Qt5 QML Controls1.4 中的 TreeView 存在诸多问题,比如节点连接的虚线不好实现,currentIndex 的设置和 changed 信号的触发等.我想主要的原因在于 ...

  8. Vue中select下拉框的默认选中项的三种情况

    在Vue中 使用select下拉框 主要靠的是 v-model 来绑定选项 option 的 value 值. select下拉框在界面的展示,我们都希望看到框中有一个值 而不是空白,比如显示 &qu ...

  9. 关于select2 默认选中 动态选中 显示,刷新选中等操作

    关于select2设置不了 显示 却能设置 因为项目原因 用到了select2 而我一小白用传统select去设置 然后百度 gogle摸索来摸索去弄了2天,最后还是找到了 为了方便查找以后总结一下 ...

  10. as3学习第二课 显示对象和显示列表

    关于显示对象 原文地址:as3学习第二课   显示对象和显示列表 作者:冰剑蓝影 一.显示对象    显示对象就是可以在舞台上显示的对象.包括直接看到的对象,如图形.文字.图片.视频.还有看不到但又真 ...

最新文章

  1. java线程触发_java线程
  2. zen3架构_AMD Zen3架构处理器的L3缓存或将翻倍到64MB
  3. GitHub开源:狗屁不通文章生成器
  4. linux 读书笔记
  5. (2.10)备份与还原--利用T-SQL进行备份还原
  6. centos 安装testlink出现:You don't have permission to access /testlink on this server
  7. Light Head R-CNN论文笔记
  8. 【转】c# [Serializable]的作用
  9. 理请求时出现未知错误.服务器返回的状态码为: 500,react-native
  10. php100教程源码,PHP100 视频教程 2012-2013版_PHP教程
  11. 容器编排技术 -- Kubernetes kubectl create secret tls 命令详解
  12. 条款01:视C++为一个语言联邦
  13. 如何自定义Struts2表单验证后的错误信息显示格式
  14. factory工厂模式之工厂方法FactoryMethod
  15. aptana手动配置python环境_Python学习1:使用Aptana构建Python开发环境
  16. 【父亲节H5】用独特的方式表达最深沉的爱!
  17. Solidworks二次开发平台 --- RyS.SwWorks [2015-09-18更新]
  18. Oracle同英超联赛数据统计和展示的结合
  19. dlna 交互步骤-转发
  20. Strange Fractions(奇怪的分数)-数论

热门文章

  1. docker镜像加速器
  2. servlet-02-HTTP协议
  3. BootstrapTable的使用教程
  4. linux的一些目录结构
  5. 木其工作室(专业程序代写服务)[转]Linux设备驱动程序学习-中断处理
  6. 阿里云解决方案架构师,讲述分布式架构云平台解决方案(附图文)
  7. 前端设计模式(1)--工厂模式
  8. css的写法 有点凌乱(养成这习惯 神马浏览器兼容都是浮云 so easy)
  9. OpenWrt加入iptables 支持过滤字符串
  10. BZOJ1861:[ZJOI2006]书架——题解