前段时间刚好需要做一个类似于QQ空间的社区分享功能,说说内容包含文字(话题、内容)、视频、图片,还需包含点赞,评论,位置信息等功能。 就采用LIstview做了一个,先来看下效果,GIF太大,CSDN传不了,请移步Gitee连接:GIF效果

1. 先来分析一下ListView中每一个条目包含的控件,请看下图


序号1:头像,ImageView,自定义为圆形即可;
序号2:用户名,TextView;
序号3:发布时间,TextView;
序号4:说说文字部分,TextView;
序号5:说说中视频或图片部分,Videoview;
序号6:点赞信息,TextView动态添加
序号7:位置信息,TextView
序号8/9/10:点赞、评论、转发,均为ImageView
序号11:评论区,TextView动态添加
序号12:评论框,EditText,其右侧图片是通过drawableRight设置的,事件监听会在后面详细说;
上面图中漏了一个,在视频正中央还需要有一个播放按钮,为ImageView,通过切换ImageView中图片实现播放与暂停切换。

2. 确定好有哪些控件后,我们用xml实现布局,文件命名为video_brower_item.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"xmlns:app="http://schemas.android.com/apk/res-auto"><LinearLayoutandroid:id="@+id/mContainer"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:paddingLeft="10dp"android:paddingRight="10dp"android:paddingTop="10dp"android:background="@android:color/white"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><com.xiaok.winterolympic.custom.CircleImageViewandroid:id="@+id/video_avatar"android:layout_width="45dp"android:layout_height="45dp"android:src="@drawable/head_picture" /><TextViewandroid:id="@+id/video_username"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="xiaok"android:textColor="#000000"android:layout_marginStart="15dp"android:textSize="24sp"android:textStyle="bold" /><TextViewandroid:id="@+id/video_date"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="20dp"android:textSize="14sp"android:text="刚刚"/></LinearLayout><TextViewandroid:id="@+id/video_descripation"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="15dp"android:textSize="16sp"android:textColor="#000000"android:text="#共迎冬奥# 冬奥"/><VideoViewandroid:id="@+id/video_view"android:layout_width="match_parent"android:layout_height="230dp"android:layout_marginTop="15dp"/><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:id="@+id/video_position"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="北京市朝阳区"android:layout_marginTop="12dp"android:layout_alignParentStart="true"android:layout_marginBottom="10dp"/><ImageViewandroid:id="@+id/video_iv_good"style="@style/VideoShareImageView"android:src="@mipmap/video_share_good"android:layout_toStartOf="@+id/video_iv_comment"android:layout_marginEnd="20dp"/><ImageViewandroid:id="@+id/video_iv_comment"style="@style/VideoShareImageView"android:src="@mipmap/video_share_comment"android:layout_toStartOf="@+id/video_iv_share"android:layout_marginEnd="20dp"/><ImageViewandroid:id="@+id/video_iv_share"style="@style/VideoShareImageView"android:src="@mipmap/video_share_share"android:layout_alignParentEnd="true"android:layout_marginEnd="10dp"/></RelativeLayout><EditTextandroid:id="@+id/video_et_comment"android:layout_width="match_parent"android:layout_height="40dp"android:hint="评论"android:textSize="14sp"android:layout_marginBottom="20dp"android:drawableRight="@drawable/video_send_picture"/></LinearLayout><ImageViewandroid:id="@+id/video_play"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/ic_record_play"android:layout_gravity="center_horizontal"android:layout_marginTop="192dp"/></FrameLayout>

效果如图:

3. 定义一个类,这里命名为VideoBrower,用于封装ListView中每个条目所用到的数据:

package com.xiaok.winterolympic.model;import java.io.Serializable;public class VideoBrower implements Serializable {private static final long serialVersionUID = 1L;private int avatarId;private String username;private String date;private String videoDescripation;private String videoPath;private String position;public VideoBrower(int avatarId, String username, String date, String videoDescripation, String videoPath, String position) {this.avatarId = avatarId;this.username = username;this.date = date;this.videoDescripation = videoDescripation;this.videoPath = videoPath;this.position = position;}public int getAvatarId() {return avatarId;}public String getUsername() {return username;}public String getDate() {return date;}public String getVideoDescripation() {return videoDescripation;}public String getVideoPath() {return videoPath;}public String getPosition() {return position;}public void setAvatarId(int avatarId) {this.avatarId = avatarId;}public void setDate(String date) {this.date = date;}public void setUsername(String username) {this.username = username;}public void setVideoDescripation(String videoDescripation) {this.videoDescripation = videoDescripation;}public void setVideoPath(String videoPath) {this.videoPath = videoPath;}public void setPosition(String position) {this.position = position;}}

这里解释下,头像我是通过封装R文件中对应的资源ID实现的,所以格式为int

4. 定义这个ListViewAdapter,命名为VideoBrowerAdapter

这里有几个点需要单独说明,

  1. VideoView中视频加载完还未播放之前,其背景一般需要显示视频的预览,通常取视频的第一帧图片作为视频预览显示在VideoView中,获取视频第一帧通常通过MediaMetadataRetriever,代码如下:
     MediaMetadataRetriever media = new MediaMetadataRetriever();Uri videoUri = Uri.parse(aData.get(position).getVideoPath()); //getVideoPath()获取的是视频的存储路径media.setDataSource(mContext,videoUri);Bitmap bitmap = media.getFrameAtTime();
  1. 在设计评论框时,我使用的是EditText加上其内置的drawableRight属性,但EditText原生并不提供关于drawable属性的监听,所以这里我通过回调onTouch,监测用户触摸的位置,进而实现drawable的交互,代码如下:
     //评论框右边发表图标holder.video_et_comment.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {// et.getCompoundDrawables()得到一个长度为4的数组,分别表示左右上下四张图片Drawable drawable = holder.video_et_comment.getCompoundDrawables()[2];//如果右边没有图片,不再处理if (drawable == null)return false;//如果不是按下事件,不再处理if (event.getAction() != MotionEvent.ACTION_UP)return false;if (event.getX() > holder.video_et_comment.getWidth()- holder.video_et_comment.getPaddingRight()- drawable.getIntrinsicWidth()){//发表String commentStr = holder.video_et_comment.getText().toString().trim();if (TextUtils.isEmpty(commentStr)){ToastUtils.showSingleToast("评论内容不能为空");}else {addView(holder, commentStr);holder.video_et_comment.setText(""); //发表完评论后编辑框清空ToastUtils.showSingleToast("发表成功!");}}return false;}});

完整代码如下:

public class VideoBrowerAdapter extends BaseAdapter {private LinkedList<VideoBrower> aData;private Context mContext;private boolean isGood = false;private boolean isVideoPlaying = false;private int commentIndex = 4;private TextView thumpUpView;public VideoBrowerAdapter(LinkedList<VideoBrower> aData, Context mContext){this.aData = aData;this.mContext = mContext;}@Overridepublic int getCount(){return aData.size();}@Overridepublic  Object getItem(int position){return null;}@Overridepublic long getItemId(int position){return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent){ViewHolder holder;if (convertView==null){convertView = LayoutInflater.from(mContext).inflate(R.layout.video_brower_item,parent,false);holder = new ViewHolder();holder.videoAvatar = convertView.findViewById(R.id.video_avatar);holder.username = convertView.findViewById(R.id.video_username);holder.videoDate = convertView.findViewById(R.id.video_date);holder.videoDescripation = convertView.findViewById(R.id.video_descripation);holder.video_view = convertView.findViewById(R.id.video_view);holder.videoPosition = convertView.findViewById(R.id.video_position);holder.videoPlay = convertView.findViewById(R.id.video_play);holder.video_iv_good = convertView.findViewById(R.id.video_iv_good);holder.video_iv_comment = convertView.findViewById(R.id.video_iv_comment);holder.video_iv_share = convertView.findViewById(R.id.video_iv_share);holder.video_et_comment = convertView.findViewById(R.id.video_et_comment);holder.mContainer = convertView.findViewById(R.id.mContainer); //拿到布局,用于动态添加ViewconvertView.setTag(holder);}else {holder = (ViewHolder)convertView.getTag();}MediaMetadataRetriever media = new MediaMetadataRetriever();Uri videoUri = Uri.parse(aData.get(position).getVideoPath());media.setDataSource(mContext,videoUri);Bitmap bitmap = media.getFrameAtTime();holder.videoAvatar.setImageResource(aData.get(position).getAvatarId());holder.username.setText(aData.get(position).getUsername());holder.videoDate.setText(aData.get(position).getDate());holder.videoDescripation.setText(aData.get(position).getVideoDescripation());holder.video_view.setBackground(new BitmapDrawable(bitmap));holder.video_view.setVideoURI(videoUri);holder.videoPosition.setText(aData.get(position).getPosition());/**响应事件*///播放视频按钮holder.videoPlay.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (holder.video_view != null){if (!isVideoPlaying){holder.videoPlay.setImageResource(R.mipmap.ic_record_stop);holder.video_view.start();holder.video_view.setBackground(null);holder.video_view.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {holder.videoPlay.setImageResource(R.mipmap.ic_record_play);}});}else {holder.video_view.stopPlayback();holder.videoPlay.setImageResource(R.mipmap.ic_record_play);}}}});//点赞holder.video_iv_good.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (!isGood){holder.video_iv_good.setImageResource(R.mipmap.video_share_good_blue);addThumpUpView(holder);Toast.makeText(mContext, "点赞成功!", Toast.LENGTH_SHORT).show();isGood = true;}else {holder.video_iv_good.setImageResource(R.mipmap.video_share_good);removeThumpUpView(holder);isGood = false;}}});//评论图片按钮holder.video_iv_comment.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//焦点移动到评论区holder.video_et_comment.requestFocus();}});//评论框右边发表图标holder.video_et_comment.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {// et.getCompoundDrawables()得到一个长度为4的数组,分别表示左右上下四张图片Drawable drawable = holder.video_et_comment.getCompoundDrawables()[2];//如果右边没有图片,不再处理if (drawable == null)return false;//如果不是按下事件,不再处理if (event.getAction() != MotionEvent.ACTION_UP)return false;if (event.getX() > holder.video_et_comment.getWidth()- holder.video_et_comment.getPaddingRight()- drawable.getIntrinsicWidth()){//发表String commentStr = holder.video_et_comment.getText().toString().trim();if (TextUtils.isEmpty(commentStr)){ToastUtils.showSingleToast("评论内容不能为空");}else {addView(holder, commentStr);holder.video_et_comment.setText(""); //发表完评论后编辑框清空ToastUtils.showSingleToast("发表成功!");}}return false;}});//分享holder.video_iv_share.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//分享说说,具体功能就不写了}});return convertView;}static class ViewHolder{CircleImageView videoAvatar;TextView username;TextView videoDate;TextView videoDescripation;VideoView video_view;TextView videoPosition;ImageView videoPlay;ImageView video_iv_good;ImageView video_iv_comment;ImageView video_iv_share;EditText video_et_comment;LinearLayout mContainer;}/*** 添加评论* @param:holder:ListView容器,用于* @param:commentStr:评论内容*/private void addView(ViewHolder holder, String commentStr){TextView view = new TextView(mContext);LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 60);lp.setMargins(0,15,0,15);view.setTextSize(14);view.setTextColor(mContext.getColor(R.color.record_comment_text));view.setText("xiaok:"+commentStr);int index = holder.mContainer.getChildCount();holder.mContainer.addView(view,index-1,lp);}private void addThumpUpView(ViewHolder holder){thumpUpView = new TextView(mContext);LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 60);lp.setMargins(0,15,0,15);thumpUpView.setTextSize(14);thumpUpView.setTextColor(mContext.getColor(R.color.record_comment_text));thumpUpView.setText("xiaok 觉得很赞");holder.mContainer.addView(thumpUpView,3,lp);}private void removeThumpUpView(ViewHolder holder){holder.mContainer.removeViewAt(3);}
}

5. 创建Activity对应的布局文件,命名为activity_video_brower.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".view.video.VideoBrowerActivity"><ListViewandroid:id="@+id/video_listview"android:layout_width="match_parent"android:layout_height="wrap_content"></ListView></LinearLayout>

6. 创建Activity文件

public class VideoBrowerActivity extends AppCompatActivity {private List<VideoBrower> aDate;private int[]videoAvatars;private String[]usernames;private String[]videoDates;private String[]videoDescripation;private String[]videoPaths;private String[]videoPosition;private String videoDescripation_01;private ListView lv_video;private ImageButton ib_back;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_video_brower);setCustomActionBar();  //加载自定义ActionBarlv_video = findViewById(R.id.video_listview);videoDescripation_01 = getIntent().getStringExtra("videoDescripation");videoAvatars = new int[]{R.drawable.head_picture,R.mipmap.video_avatar_02,R.mipmap.video_avatar_03,R.mipmap.video_avatar_04};usernames = new String[]{"xiaok","小张","王小明","李晓华"};videoDates = new String[]{"刚刚","09月17日10:12","08月22日18:15","08月22日17:42"};videoDescripation = new String[]{videoDescripation_01,"#雪容融和冰墩墩# 冬奥会和冬残奥会吉祥物来袭!","#北京冬奥# 北京赢了!2022冬奥,不见不散!!!","#冬奥来了# 冬奥宣传视频,浓浓的中国风,超赞!"};videoPaths = new String[]{FileUtils.VIDEO_01,FileUtils.VIDEO_02,FileUtils.VIDEO_03,FileUtils.VIDEO_04};videoPosition = new String[]{"北京市朝阳区","郑州市中原区","郑州市中原区","郑州市中原区"};aDate = new LinkedList<>();for (int i=0;i<videoAvatars.length;i++){aDate.add(new VideoBrower(videoAvatars[i],usernames[i],videoDates[i],videoDescripation[i],videoPaths[i],videoPosition[i]));}lv_video.setAdapter(new VideoBrowerAdapter((LinkedList<VideoBrower>)aDate,VideoBrowerActivity.this));lv_video.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {}});//左上角返回ib_back.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startActivity(new Intent(VideoBrowerActivity.this,MainPageActivity.class));}});}private void setCustomActionBar() {ActionBar.LayoutParams lp =new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT, Gravity.CENTER);View mActionBarView = LayoutInflater.from(this).inflate(R.layout.record_share_actionbar, null);ib_back = mActionBarView.findViewById(R.id.record_ib_back);ActionBar actionBar = getSupportActionBar();actionBar.setCustomView(mActionBarView, lp);actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);actionBar.setDisplayShowCustomEnabled(true);actionBar.setDisplayHomeAsUpEnabled(false);actionBar.setHomeButtonEnabled(false);actionBar.setDisplayShowTitleEnabled(false);}

项目源码地址:地址

欢迎大佬们给star!

Android ListView实现QQ空间界面(说说内包含图片、视频、点赞、评论、转发功能),结尾附源码相关推荐

  1. android仿qq动态视频播放,Android 自定义ListView实现QQ空间界面(说说内包含图片、视频、点赞、评论、转发功能)...

    前端时间刚好需要做一个类似于QQ空间的社区分享功能,说说内容包含文字(话题.内容).视频.图片,还需包含点赞,评论,位置信息等功能. 就采用LIstview做了一个,先来看下效果,GIF太大,CSDN ...

  2. QT界面免费版开源图片转文字工具程序完整版附源码

    QT界面免费版开源图片转文字工具程序完整版附源码 需求源码的朋友请留言 操作步骤如下:

  3. 集成Android 科大讯飞免费在线语音合成播报功能(附源码)

    概述 开篇先介绍一下'科大讯飞',毕竟是我家乡合肥的科技公司,我感到骄傲,更重要的是它在语音识别行业也是佼佼者,在如今人工智能横飞的时代,依然能够保持着较高水准的技术优势.在此,希望科大在AI之战中能 ...

  4. Android 实现类似于QQ空间相册的点击图片放大,再点后缩小回原来位置

    前几天看到了有人在android5.0上实现了如下图一样的效果,我自己就去搜了下.参考了国外一篇文章和国内的一篇文章,最终实现了想要的效果.具体参考的网址我已经贴到文章末尾,大家可以去英文的那个网站看 ...

  5. android listview 只加载显示的图片大小,Android ListView只加载当前屏幕内的图片(解决list滑动时加载卡顿)...

    最近在做ListView分页显示,其中包括图片 和文字(先下载解析文字内容,再异步加载图片)发现每次点击下一页后,文字内容加载完毕,马上向下滑动,由于这时后台在用线程池异步下载图片,我每页有20条,也 ...

  6. Android App开发实战项目之仿喜马拉雅的听说书App实现(超详细 附源码和演示视频)

    需要全部源码请点赞关注收藏后评论区留下QQ~~~ 一.需求分析 用户不仅能在平台上收听音频,还能成为内容创作者,总之长音频分享平台需要满足两种角色的使用:一种是作为内容创作者发布自己的音频,另一种是作 ...

  7. Android仿微信朋友圈,全文收起功能,附源码

    在众多的社交类软件中,朋友圈是必不可少的,可以与好友.同学等分享自己的日常和有意思的事情,在开发社交类App时,朋友圈发表的内容你不可能让他全部显示,全部显示的话用户体验度会非常不好,这时就要用到全文 ...

  8. Android baidu地图定位实现签到打卡功能(附源码)

    导语 本章根据baidu地图API,实现打卡功能.用到了基础地图.覆盖物.定位图层.陀螺仪方法.悬浮信息弹框. (这里原创!!!转载请表明我的原文地址~) baidu地图API地址  :Android ...

  9. Android Studio App开发之网络通信中使用POST方式调用HTTP接口实现应用更新功能(附源码 超详细必看)

    运行有问题或需要源码请点赞关注收藏后评论区留言~~~ 一.POST方式调用HTTP接口 POST方式把接口地址与请求报文分开,允许使用自定义的报文格式,由此扩大了该方式的应用场景.POST请求与GET ...

最新文章

  1. 弹窗页面PHP代码不执行,PHP代码没有被执行,而是代码显示在页面上
  2. NetCore TagHelpers标签
  3. Oracle安装配置手册
  4. 嵌入式之NB-IoT开发与应用01【移动通信网络发展概述、NB-IoT应用案例、物联网生态系统-解决方案、智慧消防项目需求分析及系统设计】
  5. 关于 SAP 电商云 Spartacus UI 修改 div 层级结果是否算是 breaking change 的问题
  6. JavaBean为什么要实现Serializable接口
  7. MySQL各个版本区别
  8. GDAL打开mdb文件失败解决方法
  9. Mybatis自动去重
  10. java zip解压抛出异常,java – ZipFile抛出错误,但ZipInputStream能够解压缩归档
  11. python提取图片文字_python实现提取图片中文字
  12. 大数据技术基础学习总结
  13. websocket简单聊天室
  14. 将本地端口映射子域名
  15. 360个人图书馆 轻松解除网页防复制
  16. 离线报表之五大看板主题需求分析(SQL版)
  17. 2021年6月1日09点00分 Xray扫描器
  18. 智能电视看凤凰卫视,不用直播源
  19. [EAI ERROR]: Cannot bind to the specified serial port /dev/ttyUSB0. process has died[pid 108767, ex
  20. python词云分析---政府工作报告关键词

热门文章

  1. Web3.0,重组互联网控制权
  2. linux下使用异步通知
  3. 未来大数据的主要应用领域,你都知道了吗?
  4. rowspan 动态变化_php – 从数据库中获取记录时的动态rowspan
  5. python制作的炫酷动画_Python+Kepler.gl轻松制作酷炫路径动画
  6. 【学习记录】UE4 蓝图实现昼夜交替和简单的雨水效果
  7. 罗胖时间的朋友跨年演讲释放的世界氢燃料电池汽车信号
  8. 注册安全工程师成绩出来了吗,注安成绩公布日期2023
  9. linux 函数 查看ttl,利用TTL值来鉴别操作系统
  10. 浅谈程序员研发与军工六性