实现炫酷的获取本地图片和相机拍照图片-自定义组件

iOS中有封装好的选择图片后长按出现动画删除效果,效果如下 
这里写图片描述 
Android找了很久都没有找到有这样效果的第三方组件,最后懒得找了还是自己实现这效果吧

选择图片后还可对图片进行剪裁 
这里写图片描述

当然,代码中还有很多不完善的地方,我接下来会继续完善这个组件的 
已经上传到开源社区,欢迎大家来Star啊~

Demo源码:传送门

设计中的碰到的一些问题和解决思路

1.如何让加号图片显示在GridView最后面

首先在调用GridAdapter构造方法时就加载加号图片

    /**
     * 图片适配器
     * @param context 上下文
     * @param imagesum 最大可添加图片数
     */
    public GridAdapter(Context context, int imagesum) {
        this.context = context;
        this.imageSum = imagesum;
        // 加号图片
        mAddBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_add_image);
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后在getCount()方法里对图片数据集合加1,在该位置上添加加号图片

    @Override
    public int getCount() {
        // 数据集合加一,在该位置上添加加号
        return imageItemData == null ? 0 : imageItemData.size() + 1;
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

最后在getView()方法中,每次显示图片时都对数据集合中的元素数量进行判断,如果数据集合的数量大于position,则表示需要显示加号图片

        if (imageItemData != null && imageItemData.size() > position) {
            // 正常图片
        } else {
            // 加号图片
        }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

这样就能保证加号图片一直在GridView最后一个item上

2.如何显示出删除按钮

在item布局时,在图片的右上角覆盖一层删除按钮,在Adapter中对这个图片的显示和隐藏进行处理

    /** 判断是否显示清除按钮 true=显示 */
    private boolean showImageClear = false;
对外提供显示和隐藏的方法
    /**
     * 设置图片显示状态
     * @param clear 图片状态
     */
    public void setClearImgShow(boolean clear) {
        showImageClear = clear;
    }

    /**
     * 图片显示状态
     * @return 状态 true=显示
     */
    public boolean getClearImgShow() {
        return showImageClear;
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

删除按钮默认不显示,当用户长按图片时就显示出来

        // 长按显示删除按钮
        mGridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                if (!(position == gridAdapter.imageItemData.size())) {
                    // 如果删除按钮已经显示了则不再设置
                    if (!gridAdapter.getClearImgShow()) {
                        gridAdapter.setClearImgShow(true);
                        gridAdapter.notifyDataSetChanged();
                    }
                }
                // 返回true,停止事件向下传播
                return true;
            }
        });

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这里需要拦截长按点击事件,把返回值设置为true,因为我们还设置了点击事件的监听,如果不拦截事件,那么长按事件结束后还会同时执行单击事件 
最后关键的一点,在GridAdapter类中的getView方法里进行控制,通过getClearImgShow方法获取删除图片是否需要显示,如果返回为true则显示出来,并获取动画实例,让图片开始执行动画效果

        if (imageItemData != null && imageItemData.size() > position) {
            // 正常显示
            // 判断是否需要显示删除按钮 ,为true则显示,并执行动画效果
            if (getClearImgShow()) {
                holder.imgclear.setVisibility(View.VISIBLE);
                CustomRotateAnim anim = CustomRotateAnim.getCustomRotateAnim();
                anim.setDuration(300);
                anim.setRepeatCount(2);
                anim.setInterpolator(new LinearInterpolator()); // 设置为匀速
                holder.img.startAnimation(anim);
            } else {
                // 关闭动画,隐藏删除按钮
                holder.img.clearAnimation();
                holder.imgclear.setVisibility(View.GONE);
            }
            holder.img.setImageBitmap(PhotoBitmapUtil.getCompressPhoto(imageItemData.get(position)));
        } else {
            ......省略......
        }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

3.如何设置当图片达到最大数时,隐藏加号按钮

在使用GridAdapter的时候,调用方需要传入一个最大图片数:

gridAdapter = new GridAdapter(MainActivity.this, 8);
mGridView.setAdapter(gridAdapter);

 
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

然后在GridAdapter中接收这个最大图片数,并在getView()方法中对加号图片的显示进行管控

        if (imageItemData != null && imageItemData.size() > position) {
            // 显示选择的图片
            ......省略......
        } else {
            // 显示加号按钮
            // 图片数达到最大限制时隐藏加号图片
            if (imageItemData.size() != imageSum) {
                holder.imgclear.setVisibility(View.GONE);   // 不显示删除按钮
                holder.img.clearAnimation();    // 去除动画
                holder.img.setImageBitmap(mAddBitmap);
            }
        }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

“gridAdapter.getCount() - 1”是因为我们在添加加号图片时加了1,所以使用时需要减1

        // 点击图片
        mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // 如果单击时删除按钮处在显示状态,则隐藏它
                if (gridAdapter.getClearImgShow()) {
                    gridAdapter.setClearImgShow(false);
                    gridAdapter.notifyDataSetChanged();
                } else {
                    if (gridAdapter.getCount() - 1 == position) {
                        // 判断是否达到了可添加图片最大数
                        if (!(gridAdapter.imageItemData.size() == gridAdapter.imageSum)) {
                            selectPhoto.showPopupSelect(mGridView);
                        }
                    } else {
                        popupViewGridPhoto(position);
                    }
                }

            }
        });

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

4.如何降低图片加载时的内存消耗量

要在GridView中显示那么多的图片,肯定是需要多图片进行压缩处理的,不然很容易出现OOM错误 
这里通过质量压缩,降低加载图片的内存大小

    /**
     * 把原图按1/5的比例压缩
     *
     * @param path 原图的路径
     * @return 压缩后的图片
     */
    public static Bitmap getCompressPhoto(String path) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        options.inSampleSize = 5;  // 图片的长宽设置为原来的五分之一
        Bitmap bmp = BitmapFactory.decodeFile(path, options);
        options = null;
        return bmp;
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

也可以通过其它的方式,可以参考这篇博客《Android避免内存溢出(Out of Memory)方法总结

5.如何防止部分手机拍照后图片被旋转的问题

测试中,部分三星手机拍摄完照片后会把图片旋转90度,这个设计实在是坑,为此还得专门为了这个问题进行处理,每次拍摄完照片后都要获取图片的旋转角度,如果图片被旋转了的话就再旋转回去 
可以参考这篇博客 
Android 解决部分手机拍照后获取的图片被旋转的问题

6.如何让图片左右摇摆

想要实现图片左右摇摆的效果,需要我们自定义Animation 
可参看这篇博客 
Android 自定义Animation实现View摇摆效果

这里就先介绍这么多,详细的解释代码注释中都有的,就不再多说啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值