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布局

<RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><Viewandroid: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.RecyclerViewandroid: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);}}@Overridepublic int getItemCount() {if (list.size() < selectMax) {return list.size() + 1;} else {return list.size();}}@Overridepublic int getItemViewType(int position) {if (isShowAddItem(position)) {return TYPE_CAMERA;} else {return TYPE_PICTURE;}}/*** 创建ViewHolder*/@Overridepublic 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;}/*** 设置值*/@Overridepublic 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() {@Overridepublic 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"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"android:orientation="vertical"><TextViewandroid: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"/><Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:background="#f5f5f5"/><TextViewandroid: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"/><TextViewandroid: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() {@Overridepublic 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() {@Overridepublic 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>() {@Overridepublic void onResult(ArrayList<LocalMedia> result) {selectList.addAll(result);//Log.d("ceshi"+RESULT_OK, String.valueOf(images));adapter.setList(selectList);adapter.notifyDataSetChanged();}@Overridepublic 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")@Overridepublic 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.mzph.cn/news/207127.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线性回归实战

3.1 使用正规方程进行求解 3.1.1 简单线性回归 公式 &#xff1a; y w x b y wx b ywxb 一元一次方程&#xff0c;在机器学习中一元表示一个特征&#xff0c;b表示截距&#xff0c;y表示目标值。 使用代码进行实现&#xff1a; 导入包 import numpy as np import matp…

中缀表达式转后缀表达式与后缀表达式计算(详解)

**中缀表达式转后缀表达式的一般步骤如下&#xff1a; 1&#xff1a;创建一个空的栈和一个空的输出列表。 2&#xff1a;从左到右扫描中缀表达式的每个字符。 3&#xff1a;如果当前字符是操作数&#xff0c;则直接将其加入到输出列表中。 4&#xff1a;如果当前字符是运算符&a…

Linux 常用命令汇总

1 linux定时任务 查看定时任务&#xff1a;crontab -l 每晚一点半执行定时任务&#xff1a; 30 1 * * * sh /var/lib/pgsql/pg_db_backup.sh >> /var/lib/pgsql/pg_db_backup.log 2>&1 配置定时任务&#xff1a;crontab -e 2 linux 内核版本查询 cat /etc/r…

我有才打造私域流量的知识付费小程序平台

在当今数字化时代&#xff0c;知识付费市场正在迅速崛起&#xff0c;而私域流量的概念也日益受到重视。私域流量指的是企业通过自有渠道获取的、能够自由支配的流量&#xff0c;这种流量具有更高的用户粘性和转化率。因此&#xff0c;打造一个基于私域流量的知识付费小程序平台…

实现:切换页面切换标题,扩展 vue-router 的类型

布局容器-页面标题 网址&#xff1a;https://router.vuejs.org/zh/guide/advanced/meta 给每一个路由添加 元信息 数据 router/index.ts const router createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{ path: /login, component: () > im…

第一启富金:新添澳大利亚(ASIC)牌照

第一启富金&#xff1a;澳大利亞證券及投資委員會&#xff08;ASIC&#xff09; GOLDWELL GLOBAL PTY LTD 是 WHOLESALE INVESTOR SERVICES PTY LTD&#xff08;CAR 編號 001304943&#xff09;的企業授權代表開發澳大利亞客戶&#xff0c;WHOLESALE INVESTOR SERVICES PTY LT…

XML是什么

XML是是什么&#xff1f; XML&#xff08;Extensible Markup Language&#xff09;&#xff0c;中文是可扩展标记语言&#xff0c;是标准通用标记语言的子集。它是一种标记语言&#xff0c;用于标记电子文档&#xff0c;使其结构化。 XML可以用来标记数据&#xff0c;定义数据…

【软件推荐】文本转语音,语音转wav,导入ue5

文字转语音 在线免费文字转语音 - TTSMaker官网 | 马克配音https://ttsmaker.cn/ 文件转换器 语音转wav Convertio — 文件转换器https://convertio.co/zh/

HarmonyOS应用程序框架——UIAbility实操

UIAbility概述 UIAbility是一种包含用户界面的应用组件&#xff0c;主要用于和用户进行交互。UIAbility也是系统调度的单元&#xff0c;为应用提供窗口在其中绘制界面。 每一个UIAbility实例&#xff0c;都对应于一个最近任务列表中的任务。 一个应用可以有一个UIAbility&…

Leetcode—901.股票价格跨度【中等】

2023每日刷题&#xff08;五十二&#xff09; Leetcode—901.股票价格跨度 算法思想 实现代码 class StockSpanner { public:stack<pair<int, int>> st;int curday -1;StockSpanner() {st.emplace(-1, INT_MAX);}int next(int price) {while(price > st.top(…

油猴(Tampermonkey)浏览器插件简单自定义脚本开发

介绍 浏览器插件&#xff0c;包括油猴插件和其他插件&#xff0c;通过它们可以实现浏览器网页的定制化与功能增强。 其他插件一般只有某种具体的功能&#xff0c;且已经写死而不能更改&#xff0c;比如Adblock插件只用于去广告。 油猴插件是一款用于管理用户脚本的插件&…

使用Rust 构建C 组件

协议解析&#xff0c;这不就很快了&#xff0c;而且原生的标准库红黑树和avl 树支持&#xff0c;异步tokio 这些库&#xff0c;编写应用组件就很快了 rust 标准库不支持 unix 的消息队列&#xff0c;但是支持 shm 和 uds&#xff0c;后者从多方面考虑都比&#xff0c;消息队列更…

教育类直播介绍

教育类直播是一种在线教育形式&#xff0c;它允许学生和教师通过实时视频通话进行互动学习。这种学习方式可以为学生提供更灵活的学习时间和地点&#xff0c;同时也可以帮助教师更好地与学生进行互动和指导。 在教育类直播中&#xff0c;学生可以通过网络与教师和其他学生进行…

c/c++中一些不常用但有用的知识

1.变长数组 bool fun(int cnt) {unsigned char data[cnt];return true; } 在 C 语言中&#xff0c;变长数组&#xff08;Variable Length Arrays&#xff0c;VLA&#xff09;是 C99 标准引入的特性&#xff0c;允许使用变量来定义数组的长度。因此&#xff0c;在 C 版本的代码…

快速在VMware虚拟机上运行Kali Linux(保姆级教程)

本期将演示如何在VMware虚拟机上快速、轻松地安装Kali Linux。Kali Linux是一款专为渗透测试和网络安全而设计的操作系统&#xff0c;拥有很多强大的工具和功能。 在运行任何虚拟机之前&#xff0c;一定要先确保已经打开主板BIOS上的虚拟化支持。 下载VMware 接着来到vmware的…

vue 一直运行 /sockjs-node/info?及 /sockjs-node/info报错解决办法

sockjs-node介绍 sockjs-node 是一个JavaScript库&#xff0c;提供跨浏览器JavaScript的API&#xff0c;创建了一个低延迟、全双工的浏览器和web服务器之间通信通道。 服务端&#xff1a;sockjs-node&#xff08;https://github.com/sockjs/sockjs-node&#xff09; 客户端&a…

[全志Tina/Linux]全志修改bootlogo分区数据从而修改bootlogo

一、需求 在不进行镜像烧录的情况下&#xff0c;通过启动项或脚本将已存在于主板的bootlogo文件更新到bootlogo分区中&#xff0c;从而实现bootlogo的更新 二、操作 1、在主板上查找bootlogo文件路径 find -name bootlogo* 实机效果&#xff1a; 2、进入文件夹路径 cd ./d…

Java网络编程——对象的序列化与反序列化

当两个进程进行远程通信时&#xff0c;彼此可以发送各种类型的数据&#xff0c;如文本、图片、语音和视频等。无论是何种类型的数据&#xff0c;都会以二进制序列的形式在网络上传送。当两个Java进程进行远程通信时&#xff0c;一个进程能否把一个Java对象发送给另一个进程呢&a…

LeetCode 每日一题 Day 6(DFS+BFS)

1466. 重新规划路线 n 座城市&#xff0c;从 0 到 n-1 编号&#xff0c;其间共有 n-1 条路线。因此&#xff0c;要想在两座不同城市之间旅行只有唯一一条路线可供选择&#xff08;路线网形成一颗树&#xff09;。去年&#xff0c;交通运输部决定重新规划路线&#xff0c;以改变…

c语言词法分析器

词法分析器&#xff08;也称为词法解析器或词法扫描器&#xff09;是编译器的一个组成部分&#xff0c;它的任务是将输入的源代码&#xff08;字符流&#xff09;分解成称为“标记”的序列&#xff0c;其中每个标记对应于源代码中的一个单词或符号。 以下是一个简单的C语言词法…