Android ListView实现QQ空间界面(说说内包含图片、视频、点赞、评论、转发功能),结尾附源码
前段时间刚好需要做一个类似于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. 定义这个ListView
的Adapter
,命名为VideoBrowerAdapter
这里有几个点需要单独说明,
VideoView
中视频加载完还未播放之前,其背景一般需要显示视频的预览,通常取视频的第一帧图片作为视频预览显示在VideoView
中,获取视频第一帧通常通过MediaMetadataRetriever
,代码如下:
MediaMetadataRetriever media = new MediaMetadataRetriever();Uri videoUri = Uri.parse(aData.get(position).getVideoPath()); //getVideoPath()获取的是视频的存储路径media.setDataSource(mContext,videoUri);Bitmap bitmap = media.getFrameAtTime();
- 在设计评论框时,我使用的是
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空间界面(说说内包含图片、视频、点赞、评论、转发功能),结尾附源码相关推荐
- android仿qq动态视频播放,Android 自定义ListView实现QQ空间界面(说说内包含图片、视频、点赞、评论、转发功能)...
前端时间刚好需要做一个类似于QQ空间的社区分享功能,说说内容包含文字(话题.内容).视频.图片,还需包含点赞,评论,位置信息等功能. 就采用LIstview做了一个,先来看下效果,GIF太大,CSDN ...
- QT界面免费版开源图片转文字工具程序完整版附源码
QT界面免费版开源图片转文字工具程序完整版附源码 需求源码的朋友请留言 操作步骤如下:
- 集成Android 科大讯飞免费在线语音合成播报功能(附源码)
概述 开篇先介绍一下'科大讯飞',毕竟是我家乡合肥的科技公司,我感到骄傲,更重要的是它在语音识别行业也是佼佼者,在如今人工智能横飞的时代,依然能够保持着较高水准的技术优势.在此,希望科大在AI之战中能 ...
- Android 实现类似于QQ空间相册的点击图片放大,再点后缩小回原来位置
前几天看到了有人在android5.0上实现了如下图一样的效果,我自己就去搜了下.参考了国外一篇文章和国内的一篇文章,最终实现了想要的效果.具体参考的网址我已经贴到文章末尾,大家可以去英文的那个网站看 ...
- android listview 只加载显示的图片大小,Android ListView只加载当前屏幕内的图片(解决list滑动时加载卡顿)...
最近在做ListView分页显示,其中包括图片 和文字(先下载解析文字内容,再异步加载图片)发现每次点击下一页后,文字内容加载完毕,马上向下滑动,由于这时后台在用线程池异步下载图片,我每页有20条,也 ...
- Android App开发实战项目之仿喜马拉雅的听说书App实现(超详细 附源码和演示视频)
需要全部源码请点赞关注收藏后评论区留下QQ~~~ 一.需求分析 用户不仅能在平台上收听音频,还能成为内容创作者,总之长音频分享平台需要满足两种角色的使用:一种是作为内容创作者发布自己的音频,另一种是作 ...
- Android仿微信朋友圈,全文收起功能,附源码
在众多的社交类软件中,朋友圈是必不可少的,可以与好友.同学等分享自己的日常和有意思的事情,在开发社交类App时,朋友圈发表的内容你不可能让他全部显示,全部显示的话用户体验度会非常不好,这时就要用到全文 ...
- Android baidu地图定位实现签到打卡功能(附源码)
导语 本章根据baidu地图API,实现打卡功能.用到了基础地图.覆盖物.定位图层.陀螺仪方法.悬浮信息弹框. (这里原创!!!转载请表明我的原文地址~) baidu地图API地址 :Android ...
- Android Studio App开发之网络通信中使用POST方式调用HTTP接口实现应用更新功能(附源码 超详细必看)
运行有问题或需要源码请点赞关注收藏后评论区留言~~~ 一.POST方式调用HTTP接口 POST方式把接口地址与请求报文分开,允许使用自定义的报文格式,由此扩大了该方式的应用场景.POST请求与GET ...
最新文章
- 弹窗页面PHP代码不执行,PHP代码没有被执行,而是代码显示在页面上
- NetCore TagHelpers标签
- Oracle安装配置手册
- 嵌入式之NB-IoT开发与应用01【移动通信网络发展概述、NB-IoT应用案例、物联网生态系统-解决方案、智慧消防项目需求分析及系统设计】
- 关于 SAP 电商云 Spartacus UI 修改 div 层级结果是否算是 breaking change 的问题
- JavaBean为什么要实现Serializable接口
- MySQL各个版本区别
- GDAL打开mdb文件失败解决方法
- Mybatis自动去重
- java zip解压抛出异常,java – ZipFile抛出错误,但ZipInputStream能够解压缩归档
- python提取图片文字_python实现提取图片中文字
- 大数据技术基础学习总结
- websocket简单聊天室
- 将本地端口映射子域名
- 360个人图书馆 轻松解除网页防复制
- 离线报表之五大看板主题需求分析(SQL版)
- 2021年6月1日09点00分 Xray扫描器
- 智能电视看凤凰卫视,不用直播源
- [EAI ERROR]: Cannot bind to the specified serial port /dev/ttyUSB0. process has died[pid 108767, ex
- python词云分析---政府工作报告关键词