当前位置:   article > 正文

【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)_android仿抖音app源码

android仿抖音app源码

需要全部代码请点赞关注收藏后评论区留言私信~~~

与传统的影视行业相比,诞生于移动互联网时代的短视频是个全新行业,它制作方便又容易传播,一出现就成为大街小巷的时髦潮流。 各行各业的人们均可通过短视频展示自己,短小精悍的视频片段原来能够容纳如此丰富的内蕴。许多人依靠短视频获得大量关注,乃至成为谋生手段,本人甚至成为网红。 这些都离不开短视频分享平台的推波助澜,尤其是一对欢喜冤家——抖音和快手,它们的使用频率甚至超过了老牌App。其中抖音的国际版TikTok更是风靡全球,它鼓励国外年轻人勇敢表现自我,成为中国企业的出海标杆。

一、需求描述

短视频分享平台需要满足两种角色的使用:

(1)一种是作为内容创作者发布自己的视频,

(2)另一种是作为用户欣赏平台上的已有视频。

还有一些点赞关注弹幕功能这里就不再赘述了 相信大家对短视频平台都不陌生

二、功能分析

短视频分享与传统的图文界面大相径庭,因为单个短视频就已经填满了整块屏幕,势必要求采取专门的方式浏览短视频,从用户界面到后台服务,短视频分享主要集成了以下App技术

(1)二代翻页视图:向上滑动浏览界面能够拉出新视频。

(2)下拉刷新控件:下拉手势会触发刷新动作获取最新发布的视频。

(3)新型播放器:ExoPlayer能够快速响应网络视频。

(4)相机视图:录制短视频需要自定义相机视图。

(5)媒体检索工具:从视频中截取某帧作为视频封面。

(6)循环视图:备选的视频各帧画面从左往右依次排开。

(7)网络通信框架:上传视频信息与获取视频列表均需与后端交互。

(8)移动数据格式JSON:通过JSON结构封装http交互数据。

下面介绍代码模块中各部分之间的关系

(1)ShortViewActivity.java:这是短视频分享的浏览首页。

(2)VideoFragment.java:这是每个短视频的碎片页。

(3)ShortTakeActivity.java:这是视频录制页面。

(4)ShortEditActivity.java:这是视频信息的编辑页面。

(5)ShortCoverActivity.java:这是视频封面的挑选页面。

(6)VideoLoadTask.java:这是视频列表的加载任务。

三、效果展示

在初始界面可以点击录制视频 录制完之后进入编辑页面,可以输入视频的名称 摘要 描述 日期等等信息  发布之后可以自己观看(此处要连接后台服务器IDEA)

 

 

 四、代码

部分代码如下 需要全部代码请点赞关注收藏后评论区留言私信~~~

短视频分享首页代码

  1. package com.example.video;
  2. import android.content.Intent;
  3. import android.os.Bundle;
  4. import android.view.WindowManager;
  5. import androidx.appcompat.app.AppCompatActivity;
  6. import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
  7. import androidx.viewpager2.widget.ViewPager2;
  8. import com.example.video.adapter.VideoPagerAdapter;
  9. import com.example.video.bean.VideoInfo;
  10. import com.example.video.task.VideoLoadTask;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. public class ShortViewActivity extends AppCompatActivity {
  14. private SwipeRefreshLayout srl_dynamic; // 声明一个下拉刷新布局对象
  15. private List<VideoInfo> mVideoList = new ArrayList<>(); // 声明一个地址列表
  16. private VideoPagerAdapter mAdapter; // 声明一个视频翻页适配器对象
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_short_view);
  21. getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 保持屏幕常亮
  22. initView(); // 初始化视图
  23. startLoad(); // 开始加载短视频
  24. }
  25. // 初始化视图
  26. private void initView() {
  27. srl_dynamic = findViewById(R.id.srl_dynamic);
  28. ViewPager2 vp2_content = findViewById(R.id.vp2_content);
  29. srl_dynamic.setOnRefreshListener(() -> startLoad()); // 设置下拉布局的下拉刷新监听器
  30. // 构建一个视频地址的翻页适配器
  31. mAdapter = new VideoPagerAdapter(this, mVideoList);
  32. vp2_content.setAdapter(mAdapter); // 设置二代翻页视图的适配器
  33. findViewById(R.id.iv_add).setOnClickListener(v ->
  34. startActivity(new Intent(this, ShortTakeActivity.class)));
  35. }
  36. // 开始加载最新的短视频
  37. private void startLoad() {
  38. // 创建一个视频列表加载任务
  39. VideoLoadTask task = new VideoLoadTask(this, videoList -> {
  40. srl_dynamic.setRefreshing(false); // 结束下拉刷新布局的刷新动作
  41. mVideoList.clear();
  42. mVideoList.addAll(videoList);
  43. mAdapter.notifyDataSetChanged(); // 通知适配器数据发生变化
  44. });
  45. task.start(); // 启动短视频列表加载任务
  46. }
  47. }

短视频任务类代码

  1. package com.example.video;
  2. import android.content.Intent;
  3. import android.hardware.camera2.CameraCharacteristics;
  4. import android.net.Uri;
  5. import android.os.Bundle;
  6. import android.text.TextUtils;
  7. import android.view.View;
  8. import android.view.animation.Animation;
  9. import android.view.animation.Transformation;
  10. import android.widget.ImageView;
  11. import android.widget.LinearLayout;
  12. import android.widget.RelativeLayout;
  13. import android.widget.TextView;
  14. import android.widget.Toast;
  15. import android.widget.VideoView;
  16. import androidx.appcompat.app.AppCompatActivity;
  17. import com.example.video.util.MediaUtil;
  18. import com.example.video.util.Utils;
  19. import com.example.video.widget.ArcView;
  20. import com.example.video.widget.Camera2View;
  21. public class ShortTakeActivity extends AppCompatActivity {
  22. private final static String TAG = "ShortTakeActivity";
  23. private RelativeLayout rl_preview; // 声明一个相对布局对象
  24. private VideoView vv_content; // 声明一个视频视图对象
  25. private RelativeLayout rl_record; // 声明一个相对布局对象
  26. private Camera2View c2v_preview; // 声明一个二代相机视图对象
  27. private TextView tv_cost; // 声明一个文本视图对象
  28. private ImageView iv_record; // 声明一个图像视图对象
  29. private ArcView av_progress; // 声明一个圆弧视图对象
  30. private LinearLayout ll_next; // 声明一个线性布局对象
  31. private int mCameraType = CameraCharacteristics.LENS_FACING_BACK; // 默认使用后置摄像头拍照
  32. private boolean isRecording = false; // 是否正在录像
  33. private int MAX_RECORD_TIME = 15; // 最大录制时长,默认15
  34. private String mVideoPath; // 待上传的视频文件路径
  35. private int CHOOSE_CODE = 3; // 只在视频库挑选视频的请求码
  36. @Override
  37. protected void onCreate(Bundle savedInstanceState) {
  38. super.onCreate(savedInstanceState);
  39. setContentView(R.layout.activity_short_take);
  40. initView(); // 初始化视图
  41. initCamera(); // 初始化相机
  42. }
  43. // 初始化视图
  44. private void initView() {
  45. findViewById(R.id.iv_back).setOnClickListener(v -> finish());
  46. rl_preview = findViewById(R.id.rl_preview);
  47. c2v_preview = findViewById(R.id.c2v_preview);
  48. vv_content = findViewById(R.id.vv_content);
  49. rl_record = findViewById(R.id.rl_record);
  50. tv_cost = findViewById(R.id.tv_cost);
  51. iv_record = findViewById(R.id.iv_record);
  52. av_progress = findViewById(R.id.av_progress);
  53. iv_record.setOnClickListener((v) -> dealRecord()); // 处理录像动作
  54. findViewById(R.id.btn_album).setOnClickListener(v -> {
  55. // 创建一个内容获取动作的意图(准备跳到系统视频库)
  56. Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
  57. intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 是否允许多选
  58. intent.setType("video/*"); // 类型为视频
  59. startActivityForResult(intent, CHOOSE_CODE); // 打开系统视频库
  60. });
  61. findViewById(R.id.iv_switch).setOnClickListener((v) -> {
  62. mCameraType = (mCameraType == CameraCharacteristics.LENS_FACING_BACK) ?
  63. CameraCharacteristics.LENS_FACING_FRONT : CameraCharacteristics.LENS_FACING_BACK;
  64. c2v_preview.switchCamera(mCameraType); // 切换摄像头
  65. });
  66. ll_next = findViewById(R.id.ll_next);
  67. findViewById(R.id.btn_cancel).setOnClickListener(v -> finish());
  68. findViewById(R.id.btn_next).setOnClickListener((v) -> {
  69. // 下面跳到视频编辑界面
  70. Intent intent = new Intent(this, ShortEditActivity.class);
  71. intent.putExtra("video_path", mVideoPath);
  72. startActivity(intent);
  73. });
  74. }
  75. // 处理录像动作
  76. private void dealRecord() {
  77. if (!isRecording) {
  78. iv_record.setImageResource(R.drawable.short_stop);
  79. c2v_preview.startRecord(MAX_RECORD_TIME, false); // 开始录像
  80. startRecordAnim(); // 播放录像动画
  81. isRecording = !isRecording;
  82. } else {
  83. rl_record.setVisibility(View.GONE);
  84. c2v_preview.stopRecord(); // 停止录像
  85. }
  86. }
  87. // 初始化相机
  88. private void initCamera() {
  89. // 初始化二代相机,并指定准备就绪监听器和停止录像监听器
  90. c2v_preview.initCamera(mCameraType, (size) -> {
  91. int adjustHeight = Utils.getScreenWidth(this) * size.getWidth() / size.getHeight();
  92. RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) c2v_preview.getLayoutParams();
  93. params.height = adjustHeight; // 根据预览尺寸调整预览窗口的高度
  94. c2v_preview.setLayoutParams(params); // 设置预览视图的布局参数
  95. }, (result) -> {
  96. runOnUiThread(() -> {
  97. isRecording = false;
  98. Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
  99. mVideoPath = c2v_preview.getVideoPath();
  100. playVideo(); // 播放视频
  101. });
  102. });
  103. }
  104. // 播放视频
  105. private void playVideo() {
  106. c2v_preview.closeCamera(); // 关闭相机
  107. rl_preview.setVisibility(View.GONE);
  108. rl_record.setVisibility(View.GONE);
  109. vv_content.setVisibility(View.VISIBLE);
  110. vv_content.setVideoURI(Uri.parse(mVideoPath)); // 设置视频视图的视频路径
  111. // 设置视频视图的就绪监听器,在播放源准备完成后,命令媒体播放器循环播放视频
  112. vv_content.setOnPreparedListener(mp -> mp.setLooping(true));
  113. vv_content.start(); // 视频视图开始播放
  114. ll_next.setVisibility(View.VISIBLE);
  115. }
  116. // 播放录像动画
  117. private void startRecordAnim() {
  118. tv_cost.setVisibility(View.VISIBLE);
  119. av_progress.setVisibility(View.VISIBLE);
  120. // 定义一个圆弧渐进动画
  121. Animation animation = new Animation() {
  122. private String costDesc=""; // 耗时描述
  123. @Override
  124. protected void applyTransformation(float interpolatedTime, Transformation t) {
  125. String cost = String.format("%.1f秒", MAX_RECORD_TIME*interpolatedTime);
  126. if (!costDesc.equals(cost)) { // 秒数发生变化
  127. costDesc = cost;
  128. tv_cost.setText(costDesc);
  129. av_progress.setAngle((int) (360*interpolatedTime)); // 设置圆弧的角度
  130. }
  131. }
  132. };
  133. animation.setDuration(MAX_RECORD_TIME*1000); // 设置动画的持续时间
  134. tv_cost.startAnimation(animation); // 开始播放动画
  135. }
  136. @Override
  137. protected void onDestroy() {
  138. super.onDestroy();
  139. c2v_preview.closeCamera(); // 关闭相机
  140. }
  141. @Override
  142. protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
  143. super.onActivityResult(requestCode, resultCode, intent);
  144. if (resultCode==RESULT_OK && requestCode==CHOOSE_CODE) { // 从视频库回来
  145. if (intent.getData() != null) { // 选择一个视频
  146. Uri uri = intent.getData(); // 获得已选择视频的路径对象
  147. // 把指定Uri的视频复制一份到内部存储空间,并返回存储路径
  148. mVideoPath = MediaUtil.copyVideoFromUri(this, uri);
  149. playVideo(); // 播放视频
  150. }
  151. }
  152. }
  153. private int mCurrentPosition = 0; // 当前的播放位置
  154. @Override
  155. protected void onResume() {
  156. super.onResume();
  157. // 恢复页面时立即从上次断点开始播放视频
  158. if (!TextUtils.isEmpty(mVideoPath) && mCurrentPosition>0 && !vv_content.isPlaying()) {
  159. vv_content.seekTo(mCurrentPosition); // 找到指定位置
  160. vv_content.start(); // 视频视图开始播放
  161. }
  162. }
  163. @Override
  164. protected void onPause() {
  165. super.onPause();
  166. // 暂停页面时保存当前的播放进度
  167. if (!TextUtils.isEmpty(mVideoPath) && vv_content.isPlaying()) { // 视频视图正在播放
  168. // 获得视频视图当前的播放位置
  169. mCurrentPosition = vv_content.getCurrentPosition();
  170. vv_content.pause(); // 视频视图暂停播放
  171. }
  172. }
  173. }

创作不易 觉得有帮助请点赞关注收藏~~~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/199849
推荐阅读
相关标签
  

闽ICP备14008679号