易生活(三)-APP—ninegridview源码阅读

易生活(三)-APP—ninegridview源码阅读

简介

作者原话

类似QQ空间,微信朋友圈,微博主页等,展示图片的九宫格控件,自动根据图片的数量确定图片大小和控件大小,使用Adapter模式设置图片,对外提供接口回调,整合了Glide和PhotoView,点击图片全屏预览大图。
该项目是根据:https://github.com/laobie/NineGridImageView 修改而成,进行了优化扩展,使代码更加简单,喜欢原作的可以去使用。同时欢迎大家下载体验本项目,如果使用过程中遇到什么问题,欢迎反馈。

在该框架的帮助下,实现的最终效果

这里写图片描述

github地址

https://github.com/jeasonlzy0216/NineGridView

综述

  • 作者通过我们传递进去的上下文和一个List对照片集合进行相关计算,对照片进行布局、质量压缩、设置监听事件等。当我们点击照片时,会把一个List集合传递到另外一个Activity中进行显示(会有相关入场出厂动画以及图片张数、当前位置等信息)。最终效果即是我们看到的效果。其实,原理很简单,但是需要扎实的基础功才能写出这样优秀的框架。

阅读模块

  • 作者给的demo中的”使用RecyclerView展示news”和”使用ListView展示Evaluation”的第二个。可以直接下载demo阅读。

源码阅读

程序入口

holder.nineGrid.setAdapter(new ClickNineGridViewAdapter(context, imageInfo));

该层职责:准备需要的参数;
需要设置一个适配器,适配器里面是一个写好的适配器参数,需要传入两个参数,一个上下文、一个List,程序通过new ClickNineGridViewAdapter(context, imageInfo)返回一个父类NineGridViewAdapter

NineGridView

  • 作者重写ViewGroup,这一块作者做了大量工作进行图片数量的判断、位置的处理、图片间距的设置、图片质量的设置等,下面进行图片宽高的处理,具体也不是看的太懂,还有其它地方的细节处理。(如何获取数据:通过传入的NineGridViewAdapter对象,持有上下文和list对象。)

    该适配器的职责:

    1. 根据参数设置排版好图片布局;

      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      int width = MeasureSpec.getSize(widthMeasureSpec);
      int height = 0;
      int totalWidth = width - getPaddingLeft() - getPaddingRight();
      if (mImageInfo != null && mImageInfo.size() > 0) {
      if (mImageInfo.size() == 1) {
      gridWidth = singleImageSize > totalWidth ? totalWidth : singleImageSize;
      gridHeight = (int) (gridWidth / singleImageRatio);
      //矫正图片显示区域大小,不允许超过最大显示范围
      if (gridHeight > singleImageSize) {
      float ratio = singleImageSize * 1.0f / gridHeight;
      gridWidth = (int) (gridWidth * ratio);
      gridHeight = singleImageSize;
      }
      } else {
      // gridWidth = gridHeight = (totalWidth - gridSpacing * (columnCount - 1)) / columnCount;
      //这里无论是几张图片,宽高都按总宽度的 1/3
      gridWidth = gridHeight = (totalWidth - gridSpacing * 2) / 3;
      }
      width = gridWidth * columnCount + gridSpacing * (columnCount - 1) + getPaddingLeft() + getPaddingRight();
      height = gridHeight * rowCount + gridSpacing * (rowCount - 1) + getPaddingTop() + getPaddingBottom();
      }
      setMeasuredDimension(width, height);
      }

    2. 通过获取到的NineGridViewAdapter对象遍历图片然后分别回调ClickNineGridViewAdapter中的图片单击事件以及相关。

代码片段1

       /** 设置适配器 */
        public void setAdapter(@NonNull NineGridViewAdapter adapter) {

            //省略代码...

             //保证View的复用,避免重复创建
            if (mImageInfo == null) {
                for (int i = 0; i < imageCount; i++) {
                    ImageView iv = getImageView(i);//这个地方调用
                    if (iv == null) return;
                    addView(iv, generateDefaultLayoutParams());
                }
            } 
            //省略代码...
        }

代码片段2

         /** 获得 ImageView 保证了 ImageView 的重用 */
        private ImageView getImageView(final int position) {
            ImageView imageView;
            if (position < imageViews.size()) {
                imageView = imageViews.get(position);
            } else {
                imageView = mAdapter.generateImageView(getContext());//回调NineGridViewAdapter中的方法进行图片简单处理
                //回调点击事件
                imageView.setOnClickListener(new OnClickListener() {

             //省略代码...
        }

适配器

new ClickNineGridViewAdapter(context, imageInfo)
该适配器的职责:
1. 负责图片的预览功能(包括入场动画、出厂动画、图片下标等),该功能通过NineGridView回调调用。

代码片段1,图片点击事件

@Override
 protected void onImageItemClick(Context context, NineGridView nineGridView, int index, List<ImageInfo> imageInfo) {
              //省略代码...
 }      

代码片段2 ,跳转代码片段

         @Override
        protected void onImageItemClick(Context context, NineGridView nineGridView, int index, List<ImageInfo> imageInfo) {
            //省略代码...
            Intent intent = new Intent(context, ImagePreviewActivity.class);
            Bundle bundle = new Bundle();
            bundle.putSerializable(ImagePreviewActivity.IMAGE_INFO, (Serializable) imageInfo);
            bundle.putInt(ImagePreviewActivity.CURRENT_ITEM, index);
            intent.putExtras(bundle);
            context.startActivity(intent);//跳转
            ((Activity) context).overridePendingTransition(0, 0);
        }

图片预览ImagePreviewActivity

  • 该部分主要处理了图片的入场动画、图片显示大小、下面的文字提醒、图片切换等效果,核心使用viewpager实现,下面是滑动事件的处理

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            //省略代码...
            viewPager.setCurrentItem(currentItem);
            viewPager.getViewTreeObserver().addOnPreDrawListener(this);
            viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    currentItem = position;//实时更新当前位置
                    tv_pager.setText(String.format(getString(R.string.select), currentItem + 1, imageInfo.size()));
                }
            });
            tv_pager.setText(String.format(getString(R.string.select), currentItem + 1, imageInfo.size()));//更改下面的提醒文字,当前第几张
        }
    

其它学习到的

  • setContentView()和addContentView() 的区别

    两者的区别主要包括两点:

    1. 以添加UI组件是否被移除
      setContentView() 会导致先前添加的被移除, 即替换性的;
      而 addContentView() 不会移除先前添加的UI组件,即是累积性的

    2. 是否控制布局参数
      addContentView() 有两个参数, 可以控制布局参数; 你指出的这个setContentView 没有接受布局参数,
      默认使用MATCH_PARENT; 不过setContentView()也有带两个参数的版本, 可以控制布局参数。

  • 在加载适配器之前会有一个空挡在加载数据,页面时空白的,用户体验不好。可以使用以下方法加载一个“正在加载..”页面。

     iew emptyView = View.inflate(this, R.layout.item_empty, null);
    addContentView(emptyView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    listView.setEmptyView(emptyView);
    
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值