android项目实战之使用框架 集成多图片、视频的上传

效果图

 实现方式,本功能使用PictureSelector 第三方库  。作者项目地址:https://github.com/LuckSiege/PictureSelector

 

1. builder.gradle 增加

implementation 'io.github.lucksiege:pictureselector:v3.11.1'

implementation 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.3@aar'
implementation 'io.reactivex.rxjava2:rxjava:2.0.0'

2. XML布局

<RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <View
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_alignTop="@+id/recycler"
                    android:layout_alignBottom="@+id/recycler"
                    android:background="@color/app_color_white" />

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/recycler"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"
                    android:overScrollMode="never" />

            </RelativeLayout>

3. 适配器,这里对GridImageAdapter进行了改进。

public class GridImageAdapter extends RecyclerView.Adapter<GridImageAdapter.ViewHolder> {
    public static final String TAG = "PictureSelector";
    public static final int TYPE_CAMERA = 1;
    public static final int TYPE_PICTURE = 2;
    private final LayoutInflater mInflater;
    private  ArrayList<LocalMedia> list = new ArrayList<>();
    private int selectMax = 9;

    /**
     * 删除
     */
    public void delete(int position) {
        try {

            if (position != RecyclerView.NO_POSITION && list.size() > position) {
                list.remove(position);
                notifyItemRemoved(position);
                notifyItemRangeChanged(position, list.size());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public GridImageAdapter(Context context, List<LocalMedia> result) {
        this.mInflater = LayoutInflater.from(context);
        this.list.addAll(result);
    }

    public void setSelectMax(int selectMax) {
        this.selectMax = selectMax;
    }

    public void setList(ArrayList<LocalMedia> list) {
        this.list = list;
    }

    public int getSelectMax() {
        return selectMax;
    }

    public ArrayList<LocalMedia> getData() {
        return list;
    }

    public void remove(int position) {
        if (position < list.size()) {
            list.remove(position);
        }
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        ImageView mImg;
        ImageView mIvDel;
        TextView tvDuration;

        public ViewHolder(View view) {
            super(view);
            mImg = view.findViewById(R.id.fiv);
            mIvDel = view.findViewById(R.id.iv_del);
            tvDuration = view.findViewById(R.id.tv_duration);
        }
    }

    @Override
    public int getItemCount() {
        if (list.size() < selectMax) {
            return list.size() + 1;
        } else {
            return list.size();
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (isShowAddItem(position)) {
            return TYPE_CAMERA;
        } else {
            return TYPE_PICTURE;
        }
    }

    /**
     * 创建ViewHolder
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View view = mInflater.inflate(R.layout.item_filter_image, viewGroup, false);
        return new ViewHolder(view);
    }

    private boolean isShowAddItem(int position) {
        int size = list.size();
        return position == size;
    }

    /**
     * 设置值
     */
    @Override
    public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
        //少于MaxSize张,显示继续添加的图标
        if (getItemViewType(position) == TYPE_CAMERA) {
            viewHolder.mImg.setImageResource(R.drawable.ic_add_image);
            viewHolder.mImg.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (mItemClickListener != null) {
                        mItemClickListener.openPicture();
                    }
                }
            });
            viewHolder.mIvDel.setVisibility(View.INVISIBLE);
        } else {
            viewHolder.mIvDel.setVisibility(View.VISIBLE);
            viewHolder.mIvDel.setOnClickListener(view -> {
                int index = viewHolder.getAbsoluteAdapterPosition();
                if (index != RecyclerView.NO_POSITION && list.size() > index) {
                    list.remove(index);
                    notifyItemRemoved(index);
                    notifyItemRangeChanged(index, list.size());
                }
            });
            LocalMedia media = list.get(position);
            int chooseModel = media.getChooseModel();
            String path = media.getAvailablePath();
            long duration = media.getDuration();
            viewHolder.tvDuration.setVisibility(PictureMimeType.isHasVideo(media.getMimeType())
                    ? View.VISIBLE : View.GONE);
            if (chooseModel == SelectMimeType.ofAudio()) {
                viewHolder.tvDuration.setVisibility(View.VISIBLE);
                viewHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds
                        (R.drawable.ps_ic_audio, 0, 0, 0);

            } else {
                viewHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds
                        (R.drawable.ps_ic_video, 0, 0, 0);
            }
            viewHolder.tvDuration.setText(DateUtils.formatDurationTime(duration));
            if (chooseModel == SelectMimeType.ofAudio()) {
                viewHolder.mImg.setImageResource(com.luck.picture.lib.R.drawable.ps_audio_placeholder);
            } else {
                RequestOptions options = RequestOptions.centerCropTransform()
                        .centerCrop()
                        .placeholder(R.color.app_color_f6)
                        .diskCacheStrategy(DiskCacheStrategy.ALL);

                Glide.with(viewHolder.itemView.getContext())
                        .load(PictureMimeType.isContent(path) && !media.isCut() && !media.isCompressed() ? Uri.parse(path)
                                : path)
                        .apply(options)
                        .into(viewHolder.mImg);
            }
            //itemView 的点击事件
            if (mItemClickListener != null) {
                viewHolder.itemView.setOnClickListener(v -> {
                    int adapterPosition = viewHolder.getAbsoluteAdapterPosition();
                    mItemClickListener.onItemClick(v, adapterPosition);
                });
            }

            if (mItemLongClickListener != null) {
                viewHolder.itemView.setOnLongClickListener(v -> {
                    int adapterPosition = viewHolder.getAbsoluteAdapterPosition();
                    mItemLongClickListener.onItemLongClick(viewHolder, adapterPosition, v);
                    return true;
                });
            }
        }
    }

    private OnItemClickListener mItemClickListener;

    public void setOnItemClickListener(OnItemClickListener l) {
        this.mItemClickListener = l;
    }

    public interface OnItemClickListener {
        /**
         * Item click event
         *
         * @param v
         * @param position
         */
        void onItemClick(View v, int position);

        /**
         * Open PictureSelector
         */
        void openPicture();
    }

    private OnItemLongClickListener mItemLongClickListener;

    public void setItemLongClickListener(OnItemLongClickListener l) {
        this.mItemLongClickListener = l;
    }
}
4. 布局空间初始化
 FullyGridLayoutManager manager = new FullyGridLayoutManager(mContext, 3, GridLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(manager);
        adapter = new GridImageAdapter(getContext(), mData);
        adapter.setSelectMax(maxSelectNum);
        mRecyclerView.setAdapter(adapter);
        imageEngine = GlideEngine.createGlideEngine();

5. 点击增加弹框布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_album"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/shape_album"
            android:gravity="center"
            android:padding="15dp"
            android:text="相册"
            android:textSize="16sp"/>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#f5f5f5"/>

        <TextView
            android:id="@+id/tv_camera"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/shape_camera"
            android:gravity="center"
            android:padding="15dp"
            android:text="拍照"
            android:textSize="16sp"/>

        <TextView
            android:id="@+id/tv_cancel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:background="@drawable/shape_cancel"
            android:gravity="center"
            android:padding="15dp"
            android:text="取消"
            android:textSize="16sp"/>

    </LinearLayout>

</LinearLayout>

6. 弹框页面初始化

 View bottomView = View.inflate(mContext, R.layout.layout_bottom_dialog, null);
        TextView mAlbum = bottomView.findViewById(R.id.tv_album);
        TextView mCamera = bottomView.findViewById(R.id.tv_camera);
        TextView mCancel = bottomView.findViewById(R.id.tv_cancel);

        pop = new PopupWindow(bottomView, -1, -2);
        pop.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        pop.setOutsideTouchable(true);
        pop.setFocusable(true);
        WindowManager.LayoutParams lp = getActivity().getWindow().getAttributes();
        lp.alpha = 0.5f;
        getActivity().getWindow().setAttributes(lp);
        pop.setOnDismissListener(new PopupWindow.OnDismissListener() {

            @Override
            public void onDismiss() {
                WindowManager.LayoutParams lp = getActivity().getWindow().getAttributes();
                lp.alpha = 1f;
                getActivity().getWindow().setAttributes(lp);
            }
        });
        pop.setAnimationStyle(R.style.main_menu_photo_anim);
        pop.showAtLocation(getActivity().getWindow().getDecorView(), Gravity.BOTTOM, 0, 0);

7.  弹框页面监听初始化

View.OnClickListener clickListener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                switch (view.getId()) {
                    case R.id.tv_album:
                        //相册
                        Log.d("打开相册","sss");
                        PictureSelector.create(GoodItemTitleFragment.this)
                                .openGallery(SelectMimeType.ofImage())
                                .setImageEngine(GlideEngine.createGlideEngine())
                                .setMaxSelectNum(maxSelectNum)
                                .setMinSelectNum(1)
                                .setImageSpanCount(4)
                                .forResult(new OnResultCallbackListener<LocalMedia>() {

                                               @Override
                                               public void onResult(ArrayList<LocalMedia> result) {
                                                   selectList.addAll(result);
                                                   //Log.d("ceshi"+RESULT_OK, String.valueOf(images));
                                                   adapter.setList(selectList);
                                                   adapter.notifyDataSetChanged();
                                               }

                                               @Override
                                               public void onCancel() {

                                               }
                                           });
                       /** PictureSelector.create(GoodItemTitleFragment.this)
                                .openGallery(PictureMimeType.ofImage())
                                .maxSelectNum(maxSelectNum)
                                .minSelectNum(1)
                                .imageSpanCount(4)
                                .selectionMode(PictureConfig.MULTIPLE)
                                .forResult(PictureConfig.CHOOSE_REQUEST);**/
                        break;
                    case R.id.tv_camera:
                        //拍照
                        Log.d("打开拍照","sss");
                        PictureSelector.create(GoodItemTitleFragment.this)
                                .openCamera(SelectMimeType.ofVideo())
                                .forResultActivity(PictureConfig.REQUEST_CAMERA);
                        /**PictureSelector.create(GoodItemTitleFragment.this)
                                .openCamera(PictureMimeType.ofImage())
                                .forResult(PictureConfig.CHOOSE_REQUEST);**/
                        break;
                    case R.id.tv_cancel:
                        //取消
                        closePopupWindow();
                        break;
                }
                closePopupWindow();
            }
        };

8. 增加拍照回调,不加这个图片回调不成功哦。

@SuppressLint("RestrictedApi")
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d("ceshi"+requestCode,"111");
        Log.d("ceshi"+resultCode,"222");
        //Log.d("ceshi"+RESULT_OK,"333");
        List<LocalMedia> images;
        if (resultCode == -1) {
            //Log.d("ceshi"+RESULT_OK,"111");
            if (requestCode == PictureConfig.REQUEST_CAMERA) {// 图片选择结果回调
                images = PictureSelector.obtainSelectorList(data);
                selectList.addAll(images);
                //Log.d("ceshi"+RESULT_OK, String.valueOf(images));
                adapter.setList(selectList);
                adapter.notifyDataSetChanged();
            }
        }
    }

本功能涉及的功能较多,用了几天的时间算集成完。欢迎点赞、转发、首次。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/228678.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Rusty Tuesday :Rust 基金会一行来访 Databend Labs,共话技术创新!

在当今快速发展的技术浪潮中&#xff0c;Rust 作为一种新兴的编程语言&#xff0c;凭借其卓越的内存安全特性和高效的性能&#xff0c;吸引了全球开发者的广泛关注。2023 年 12 月 05 日&#xff0c;由 Databend Labs 主办的首届 Rusty Tuesday 活动正式在北京揭开序幕。 在本…

关于微信/支付宝等平台验签/签名sign生成算法

引言 我们在日常工作中经常会遇到对接微信平台、支付宝平台、或者自己对外开放一个api服务&#xff0c;那么这里经常会出现一个名字&#xff1a;sgin&#xff08;签名&#xff09;。 举个栗子 这是微信支付统一下单接口文档&#xff0c;最简单的理解就是&#xff0c;服务端为…

52 代码审计-PHP项目类RCE及文件包含下载删除

目录 漏洞关键字:演示案例:xhcms-无框架-文件包含跨站-搜索或应用-includeearmusic-无框架-文件下载-搜索或应用功能-down等zzzcms-无框架-文件删除RCE-搜索或应用-unlink、eval 漏洞关键字: SQL注入&#xff1a; select insert update mysql_query mysql等 文件上传&#xff…

全自动网印机配件滚珠螺杆起什么作用?

全自动网印机配件主要包括印刷网板、墨水或油墨箱、墨水或油墨管道、传动部件、移动部件、传动系统、控制系统、安全保护装置等等这些。 滚珠螺杆是一种精密的传动元件&#xff0c;能够将电机的旋转运动转化为线性运动&#xff0c;从而驱动印刷机的工作台进行精确的移动&#x…

正则表达式详细讲解

目录 一、正则表达式概念 二、八元素 1、普通字符&#xff1a; 2、元字符&#xff1a; 3、通配符 .&#xff1a; 4、字符类 []&#xff1a; 5、量词&#xff1a; 6、锚点 ^ 和 $&#xff1a; 7、捕获组 ()&#xff1a; 8、转义字符 \&#xff1a; 三、日常使用的正则…

【USRP】5G / 6G OAI 系统 5g / 6G OAI system

面向5G/6G科研应用 USRP专门用于5G/6G产品的原型开发与验证。该系统可以在实验室搭建一个真实的5G 网络&#xff0c;基于开源的代码&#xff0c;专为科研用户设计。 软件无线电架构&#xff0c;构建真实5G移动通信系统 X410 采用了目前流行的异构式系统&#xff0c;融合了FP…

unity 2d 入门 飞翔小鸟 小鸟跳跃 碰撞停止挥动翅膀动画(十)

1、切换到动画器 点击make transition和exit关联起来 2、设置参数 勾选掉Has Exit Time 3、脚本给动画器传参 using System.Collections; using System.Collections.Generic; using UnityEngine;public class Fly : MonoBehaviour {//获取小鸟&#xff08;刚体&#xff09;p…

前端学习微信小程序开发

1.微信小程序项目结构 2.WXML和HTML的区别 3.WXSS与CSS的区别 4.小程序中的.js文件 5.小程序的宿主环境 宿主环境是指程序运行所必须的依赖环境&#xff0c;因此手机微信时小程序的宿主环境。小程序宿主环境包含了通信模型、运行机制、组件、API。 &#xff08;1&#xff09;…

OpenAI的Sam Altman,获《时代》2023年度最佳CEO

12月7日&#xff0c;《时代》周刊在官网公布了2023年最佳CEO——OpenAI的Sam Altman。 此外&#xff0c;梅西入选了年度最佳运动员&#xff0c;Taylor Swift入选年度最佳人物&#xff0c;Alex Newell获年度突破奖。 《时代》周刊曾在今年的9月8日发布了“2023年AI领域最有影响…

轮播插件Slick.js使用方法详解

相比于Swiper而选择使用Slick.js的原因主要是因为其兼容不错并且在手机端的滑动效果更顺畅 参数&#xff1a; 1.基本使用&#xff1a;一般使用只需前十个属性 $(.box ul).slick({autoplay: true, //是否自动播放pauseOnHover: false, //鼠标悬停暂停自动播放speed: 1500, //…

【广州华锐互动】VR煤矿生产事故体验系统为矿工提供一个身临其境的安全实训环境

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐走进我们的生活&#xff0c;为我们带来了前所未有的沉浸式体验。在许多领域&#xff0c;如教育、医疗、娱乐等&#xff0c;VR技术都发挥着重要作用。然而&#xff0c;当这项技术被用于模拟煤矿坍…

前端打包环境配置步骤

获取node安装包并解压 获取node安装包 wget https://npmmirror.com/mirrors/node/v16.14.0/node-v16.14.0-linux-x64.tar.xz 解压 tar -xvf node-v16.14.0-linux-x64.tar.xz 创建软链接 sudo ln -s 此文件夹的绝对路径/bin/node /usr/local/bin/node&#xff0c;具体执行如下…

c语言详解牛顿迭代法以及求解倒数和平方根

Newtons iteration method 是在实数域和复数域利用切线不断逼近方程根的一种求高次曲线方程的方法&#xff0c;区别于梯度下降法&#xff0c;它是二阶导&#xff0c;收敛速度比较快&#xff0c;对于非凸函数&#xff0c;牛顿法容易受到鞍点或者最大值点的吸引。由于牛顿迭代法是…

碳化硅MOS管在三相逆变器上的应用-REASUNOS瑞森半导体

一、前言 三相逆变是指转换出的交流电压为三相&#xff0c;即AC380V&#xff0c;三相电是由三个频率相同、振幅相等、相位依次互差120度的交流电势组成。 三相逆变器的定义是将直流电能转换为交流电能的转换器&#xff0c;其基本原理就是SPWM&#xff0c;硬件架构为四个功率模…

【PyTorch】多层感知机

文章目录 1. 理论介绍1.1. 背景1.2. 多层感知机1.3. 激活函数1.3.1. ReLU函数1.3.2. sigmoid函数1.3.3. tanh函数 2. 代码实现2.1. 主要代码2.2. 完整代码2.2. 输出结果 1. 理论介绍 1.1. 背景 许多问题要使用线性模型&#xff0c;但无法简单地通过预处理来实现。此时我们可以…

暖雪-终业游戏攻略 开荒职业无量尊者圣物搭配(60亿秒伤)

本攻略基本没有用到dlc2的圣物,便于前期开荒,远程攻击难度低(本体也能用这套搭配) 圣物搭配&面板展示 开局可以选择遗物的可以选:堕龙(放三号位) 核心: 灵玉/青龙力量: 玄武/青龙/飞蝗剑/灵玉/朱雀敏捷: 堕龙功效: 憎恨之心 圣物优先级越靠前的越好 武器选择 回魂-搭…

Sublime Text 卡顿

复制下方代码&#xff0c;保存后重启Sublime Text {"non_blocking" : "true","live_mode" : "false" }

28. Python Web 编程:Django 基础教程

目录 安装使用创建项目启动服务器创建数据库创建应用创建模型设计路由设计视图设计模版 安装使用 Django 项目主页&#xff1a;https://www.djangoproject.com 访问官网 https://www.djangoproject.com/download/ 或者 https://github.com/django/django Windows 按住winR 输…

基于SpringBoot+Vue学生成绩管理系统前后端分离(源码+数据库)

一、项目简介 本项目是一套基于SpringBootVue学生成绩管理系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试&#xff0c;确…

OpenCL学习笔记(二)手动编译开发库(win10+vs2019)

前言 有时需求比较特别&#xff0c;可能需要重新编译opencl的sdk库。本文档简单记录下win10下&#xff0c;使用vs2019编译的过程&#xff0c;有需要的小伙伴可以参考下 一、获取源码 项目地址&#xff1a;GitHub - KhronosGroup/OpenCL-SDK: OpenCL SDK 可以直接使用git命令…
最新文章