2019独角兽企业重金招聘Python工程师标准>>>

#Android学习-手把手教学实现仿微信发带图片朋友圈的UI设计#

功能需求

最近自己在开发一个社交APP,发送动态(类似朋友圈)是社交APP必备的一个功能,而自己在开发过程中也需要开发到这一个功能,但是在开发中遇到了一个问题,就是如何绘制一个类似朋友群那样动态添加图片,并加号随着自己的图片增加而后移这一个UI,而这篇小文就是教你如何制作一个仿朋友圈发带图朋友圈的UI设计。注意,这是UI设计,并不是实现图片上传功能。

当然,如果你想知道如何实现图片上传到服务器,请看我的另一篇文章:Android学习-使用Async-Http实现图片压缩并上传功能。个人水平有限,如有不足的地方,欢迎交流,勿喷。

效果图

按照惯例,先上效果图。

困难

在自己开发学习过程中,主要遇到了两个难点:

  1. 添加过多图片时,会出现OOM。
  2. 如何动态修改图片展示栏的高度。
  3. 加号如何伴随图片的增加而后移。
  4. 如何保证最多添加照片为9张。

难点解决

添加过多图片时,会出现OOM

出现第一种情况的原因很简单,就是随着我们手机的像素越来越高,图片的大小也越来越大,我们普通的机拍出来照片至少也有1~2M,更不说像素高的手机。而对于一个安卓应用来说,由于手机设备的限制,一般应用使用的RAM不能超过某个设定值,不同产商默认值不太一样,一般常见的有16M,24M,32M,48M。所以一个Activity中加载几张高清原图,就会报Out Of Memory 错误,也就是所谓的OOM错误。所以知道了这个问题之后我们就很容易解决了,我们就可以先将图片压缩,然后再使用ImageView加载压缩后的图片即可。而我们这里是通过对图片的尺寸进行压缩实现图片的压缩,这里大概说一下。

  1. 要对图片压缩,首先要先将BitmapFactory.Options中的inJustDecodeBounds设置为true。

     final BitmapFactory.Options options = new BitmapFactory.Options();// 若要对图片进行压缩,必须先设置Option的inJustDecodeBounds为trueoptions.inJustDecodeBounds = true;
    
  2. 然后通过BitmapFactory中decodeFile方法来获取到照片的高度和宽度,这里只要存进一个图片地址即可。获取图片地址这里就不详讲了。

     BitmapFactory.decodeFile(pathName,options)
    
  3. 然后需要对BitmapFactory.Options中的inSampleSize根据你需要压缩比例进行设置,options.inSampleSize是图片的压缩比,例如原来大小是100 * 100,options.inSampleSize为1,则不变,options.inSampleSize为2,则压缩成50 * 50。而我这里是根据自己设置最低宽度和最低高度来获取inSampleSize的值:

     private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {final int height = options.outHeight;final int width = options.outWidth;int inSampleSize = 1;if (height > reqHeight || width > reqWidth) {//首先获取原图高度和宽度的一半final int halfHeight = height / 2;final int halfWidth = width / 2;//循环,如果halfHeight和halfWidth同时大于最小宽度和最小高度时,inSampleSize乘2,//最后得到的宽或者高都是最接近最小宽度或者最小高度的while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {inSampleSize *= 2;}}return inSampleSize;}
    
  4. 获取到inSampleSize值之后,重新设置options.inJustDecodeBounds为false,不能修改option,调用BitmapFactory中的decodeFile方法即可获取到压缩后的照片,这样在加载图片时就可以避免OOM的出现了。

     options.inJustDecodeBounds = false;// 根据options重新加载图片Bitmap src = BitmapFactory.decodeFile(pathName, options);
    

综上,我将按尺寸压缩照片的功能包装成BitmapUtil类,在使用时直接调用即可。

public class BitmapUtils {private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {final int height = options.outHeight;final int width = options.outWidth;int inSampleSize = 1;if (height > reqHeight || width > reqWidth) {final int halfHeight = height / 2;final int halfWidth = width / 2;while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {inSampleSize *= 2;}}return inSampleSize;}/*** 根据Resources压缩图片* * @param res* @param resId* @param reqWidth* @param reqHeight* @return*/public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(res, resId, options);options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);options.inJustDecodeBounds = false;Bitmap src = BitmapFactory.decodeResource(res, resId, options);return src;}/*** 根据地址压缩图片* * @param pathName* @param reqWidth* @param reqHeight* @return*/public static Bitmap decodeSampledBitmapFromFd(String pathName, int reqWidth, int reqHeight) {final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(pathName, options);options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);options.inJustDecodeBounds = false;Bitmap src = BitmapFactory.decodeFile(pathName, options);return src;}
}

如何动态修改图片展示栏的高度

如何动态修改图片展示栏的高度,首先我说一下我是使用GridView来实现图片栏的展示,所以我们可以在第一次加载GridView时可以获取到下图的参数,大家看图会容易理解一点。

  • 我们的照片如果只有一栏,则GridView的高度不变
  • 如果照片有两栏,则高度设置为gridViewH * 2 - (gridViewH - imageViewH) / 2
  • 如果有三栏,则GrideView的高度设置为gridViewH * 3 - (gridViewH - imageViewH)

  1. 我们在第一次加载GridView时记录GridView的高度GridViewH。

     LinearLayout.LayoutParams params =(android.widget.LinearLayout.LayoutParams) mGridView.getLayoutParams();gridViewH = params.height;
    
  2. 同时记录ImageView的高度

     RelativeLayout.LayoutParams params = (android.widget.RelativeLayout.LayoutParams) holder.imageView.getLayoutParams();imageViewH = params.height;
    
  3. 则上下的边距为

     (gridViewH - imageViewH) / 2
    
  4. 将它写成一个方法,在每次getView()方法中调用即可。

     private void setGridView() {LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) mGridView.getLayoutParams();if (data.size() < 4) {lp.height = gridViewH;} else if (data.size() < 8) {lp.height = gridViewH * 2 - (gridViewH - imageViewH) / 2;} else {lp.height = gridViewH * 3 - (gridViewH - imageViewH);}mGridView.setLayoutParams(lp);}
    

加号如何伴随图片的增加而后移

因为我的数据源是List<Bitmap>,所以可以这么做:

  • 当第一次加载时,List中只有一张加号的照片

  • 当添加了照片之后,List先移除加号照片,再添加照片,最后再把加号照片添加进去

        data.remove(data.size() - 1);Bitmap bp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_addpic);data.add(newBp);data.add(bp);//将路径设置为空,防止在手机休眠后返回Activity调用此方法时添加照片photoPath = null;adapter.notifyDataSetChanged();
    

如何保证最多添加照片为9张

这个问题只需要在每次添加之前判断数据源的大小是否为10(包括加号照片,大小就为10)。

if (data.size() == 10) {Toast.makeText(MainActivity.this, "图片数9张已满", Toast.LENGTH_SHORT).show();
} else {if (position == data.size() - 1) {Toast.makeText(MainActivity.this, "添加图片", Toast.LENGTH_SHORT).show();// 选择图片Intent intent = new Intent(Intent.ACTION_PICK, null);intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");startActivityForResult(intent, 0x1);} else {Toast.makeText(MainActivity.this, "点击第" + (position + 1) + " 号图片", Toast.LENGTH_SHORT).show();}
}

界面

activity_main.xml

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#F3F6F8"android:orientation="vertical" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical" ><ImageViewandroid:layout_width="match_parent"android:layout_height="1dp"android:layout_marginTop="2dp"android:src="#E4E3E3" /><EditTextandroid:id="@+id/content_et"android:layout_width="fill_parent"android:layout_height="120dp"android:background="#FFFFFF"android:gravity="top"android:hint="随手说出你此刻的心声..."android:maxLength="500"android:padding="5dp"android:singleLine="false"android:textColor="#000000"android:textSize="20sp" /><ImageViewandroid:layout_width="match_parent"android:layout_height="1dp"android:src="#E4E3E3" /><ImageViewandroid:layout_width="match_parent"android:layout_height="1dp"android:layout_marginTop="10dp"android:src="#E4E3E3" /><GridViewandroid:id="@+id/gridView1"android:layout_width="fill_parent"android:layout_height="100dp"android:background="#FFFFFF"android:columnWidth="90dp"android:gravity="center"android:horizontalSpacing="5dp"android:numColumns="4"android:padding="10dp"android:stretchMode="columnWidth"android:verticalSpacing="5dp" ></GridView><ImageViewandroid:layout_width="match_parent"android:layout_height="1dp"android:src="#E4E3E3" /><Buttonandroid:id="@+id/send_btn"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_marginLeft="35dp"android:layout_marginRight="35dp"android:layout_marginTop="20dp"android:background="@drawable/send_btn_selector"android:gravity="center"android:text="发送"android:textColor="#FFFFFF"android:textSize="20sp" /></LinearLayout></ScrollView>

griditem.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="80dp"android:layout_height="80dp"android:descendantFocusability="blocksDescendants"android:gravity="center" ><ImageViewandroid:id="@+id/imageView1"android:layout_width="80dp"android:layout_height="80dp"android:scaleType="centerCrop"android:src="@drawable/ic_addpic" /></RelativeLayout>

Demo下载

Github:https://github.com/ryanlijianchang/TestUpload

CSDN: http://download.csdn.net/detail/ljcitworld/9549313

后话

博主只是实现了这一个UI界面,我们开发过程中肯定要实现图片,文字的上传等,这里博主就不再详述了,大家可以看我的另一篇博文Android学习-使用Async-Http实现图片压缩并上传功能,就这个例子而言,大家如果需要上传多张照片,就可以在添加完照片之后将bitmap存起来,然后通过循环容器的大小,然后每一张图片再上传到服务器即可。还是那句话,个人能力有限,欢迎大家一起交流学习,我也会虚心接纳大家的指教,不喜勿喷。

参考资料

Android Developer:Loading Large Bitmaps Efficiently

转载于:https://my.oschina.net/ryaneLee/blog/691288

Android学习-手把手教学实现仿微信发带图片朋友圈的UI设计相关推荐

  1. Android初学二之仿微信APP实现RecyclerView控件的设计开发,实现点击事件及图片瀑布流

    目录 0 实验环境 1 界面展示 2 功能说明 3 核心代码 3.1 实现RecyclerView控件的设计开发 3.2 添加了文字库assets 3.3 实现点击事件对item中的每个LinearL ...

  2. flutter图片聊天泡泡_Flutter/dart聊天实例|仿微信界面|红包|朋友圈

    FlutterChatroom项目是基于flutter+dart+image_picker等技术实现的仿微信app聊天室实战项目. 一.技术框架编码/技术:Vscode + Flutter 1.12. ...

  3. uniapp可以封装组件嘛_uniapp聊天App实例|vue+uniapp仿微信界面|红包|朋友圈

    一.功能阐述 今天给大家分享的是基于UniApp+Vue+Vuex+swiper+uniPop等技术开发的仿微信原生App聊天室|仿微信聊天界面实例项目uniapp-chatroom,实现了发送图文消 ...

  4. flutter 微信语言选择_Flutter/dart聊天实例|仿微信界面|红包|朋友圈

    FlutterChatroom项目是基于flutter+dart+image_picker等技术实现的仿微信app聊天室实战项目. 一.技术框架编码/技术:Vscode + Flutter 1.12. ...

  5. imchat视频聊天室 linux,基于Nuxt+Vant聊天模板|nuxt.js仿微信界面|红包|朋友圈

    项目说明 > [NuxtIMChat项目]是基于vue.js+nuxt.js+vuex+webpack+vant-ui开发的仿微信聊天实例.实现了消息发送.图片/视频预览.下拉刷新/长按弹窗.朋 ...

  6. Android仿微信上传图片发朋友圈

    添加依赖 implementation 'com.github.lovetuzitong:MultiImageSelector:1.2' 权限 <uses-permission android: ...

  7. 仿微信选取图片发表朋友圈功能

    一.思路 第一,图片拖拽位置互换/删除,参照第三方: 第二,图片用scrollview浏览,缩放用zoomToRect,不用CGAffineTransformScale: 其次,还要返回当前缩放图片 ...

  8. Android 仿微信裁剪图片

    在很多App 中,需要注册登录,那么就免不了 设置用户的头像.头像无非就是方形 或者 圆形,那么就诞生了这样一个需求: 从相册中选择一张图片 中间区域是圆形 或者 方形的透明裁剪框 裁剪框周围是阴影 ...

  9. android 仿微信选取相册_Android 实现一个仿微信的图片选择器

    现在大部分的App都上传图片的功能,比如设置用户头像.聊天发送图片.发表动态.论坛帖子等.上传图片需要先从选择手机中选择要上传的图片,所以图片选择器在App中是很常见的组件,一般的手机都会自带一个图片 ...

  10. Android仿微信聊天记录“图片及视频”默认最新图片从底部显示(时间排序升序)

    Android仿微信聊天记录"图片及视频"默认最新图片从底部显示(时间排序升序) 1.设置recycler的LinearLayoutManager LinearLayoutMana ...

最新文章

  1. CentOS7.3 安装配置 Nginx、MariaDB、PHP
  2. 百度UEditor编辑器关闭抓取远程图片功能(默认开启)
  3. C++——static
  4. 服务器监听端口信息,服务器监听端口信息
  5. 液冷模块是什么?有什么作用与意义?
  6. ogg的孩子-无损音频编解码flac
  7. C语言 · 前10名
  8. Windows Forms、MFC、WTL、WxWidgets、Qt、GTK综合比较
  9. fiddler启用过滤规则只显示想要的接口数据
  10. 【C++】简易GIF生成器(斗图神器!必备!!!)持续更新~
  11. 2020-2023保时捷Taycan维修手册电路图技术培训手册用户手册电动汽车技术资料
  12. 洛谷 p4234 最小差值生成树
  13. ibm tivoli_使用Tivoli®Composite Application Manager监视Tivoli®Access Manager WebSEAL服务器事务以进行响应时间跟踪
  14. 同一个按钮点击多次不同效果_如何解决竞价推广中的恶意点击?
  15. 12v继电器驱动电路
  16. 轮循与连接-- 细雪之舞
  17. 手把手教你如何电脑安装android,怎么在电脑上玩android游戏?安卓模拟器怎么安装?...
  18. 基于51单片机的火焰报警器
  19. 第一次使用linux电脑,计算机基础与Linux初次亲密接触第一天(马哥)
  20. mybatis查询数据库返回数据全为null

热门文章

  1. 用安卓手机搭建一个可用渗透测试环境/安卓手机搭建linux环境
  2. html5 电子白板 直播,HTML5 canvas教程 如何实现电子白板
  3. win10 mysql 入站规则_WIn10防火墙入站规则设置无效
  4. 云主机是什么,怎么才能购买性价比高的云主机
  5. 手把手教你U盘装Raid系统
  6. Windows XP 系统下使用宽带上网真方便
  7. The server encountered an internal error that prevented it from fulfilling this request的一种解决办法
  8. Note_Master-Detail Application(iOS template)_05_ YJYMasterViewController.m
  9. 网页在线视频播放大全
  10. 计数排序CountingSort