我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

【Android App】实战项目之仿抖音的短视频分享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)

 

 

 四、代码

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

短视频分享首页代码

package com.example.video;import android.content.Intent;import android.os.Bundle;import android.view.WindowManager;import androidx.appcompat.app.AppCompatActivity;import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;import androidx.viewpager2.widget.ViewPager2;import com.example.video.adapter.VideoPagerAdapter;import com.example.video.bean.VideoInfo;import com.example.video.task.VideoLoadTask;import java.util.ArrayList;import java.util.List;public class ShortViewActivity extends AppCompatActivity {    private SwipeRefreshLayout srl_dynamic; // 声明一个下拉刷新布局对象    private List mVideoList = new ArrayList<>(); // 声明一个地址列表    private VideoPagerAdapter mAdapter; // 声明一个视频翻页适配器对象    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_short_view);        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 保持屏幕常亮        initView(); // 初始化视图        startLoad(); // 开始加载短视频    }    // 初始化视图    private void initView() {        srl_dynamic = findViewById(R.id.srl_dynamic);        ViewPager2 vp2_content = findViewById(R.id.vp2_content);        srl_dynamic.setOnRefreshListener(() -> startLoad()); // 设置下拉布局的下拉刷新监听器        // 构建一个视频地址的翻页适配器        mAdapter = new VideoPagerAdapter(this, mVideoList);        vp2_content.setAdapter(mAdapter); // 设置二代翻页视图的适配器        findViewById(R.id.iv_add).setOnClickListener(v ->                startActivity(new Intent(this, ShortTakeActivity.class)));    }    // 开始加载最新的短视频    private void startLoad() {        // 创建一个视频列表加载任务        VideoLoadTask task = new VideoLoadTask(this, videoList -> {            srl_dynamic.setRefreshing(false); // 结束下拉刷新布局的刷新动作            mVideoList.clear();            mVideoList.addAll(videoList);            mAdapter.notifyDataSetChanged(); // 通知适配器数据发生变化        });        task.start(); // 启动短视频列表加载任务    }}

短视频任务类代码

package com.example.video;import android.content.Intent;import android.hardware.camera2.CameraCharacteristics;import android.net.Uri;import android.os.Bundle;import android.text.TextUtils;import android.view.View;import android.view.animation.Animation;import android.view.animation.Transformation;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.RelativeLayout;import android.widget.TextView;import android.widget.Toast;import android.widget.VideoView;import androidx.appcompat.app.AppCompatActivity;import com.example.video.util.MediaUtil;import com.example.video.util.Utils;import com.example.video.widget.ArcView;import com.example.video.widget.Camera2View;public class ShortTakeActivity extends AppCompatActivity {    private final static String TAG = "ShortTakeActivity";    private RelativeLayout rl_preview; // 声明一个相对布局对象    private VideoView vv_content; // 声明一个视频视图对象    private RelativeLayout rl_record; // 声明一个相对布局对象    private Camera2View c2v_preview; // 声明一个二代相机视图对象    private TextView tv_cost; // 声明一个文本视图对象    private ImageView iv_record; // 声明一个图像视图对象    private ArcView av_progress; // 声明一个圆弧视图对象    private LinearLayout ll_next; // 声明一个线性布局对象    private int mCameraType = CameraCharacteristics.LENS_FACING_BACK; // 默认使用后置摄像头拍照    private boolean isRecording = false; // 是否正在录像    private int MAX_RECORD_TIME = 15; // 最大录制时长,默认15秒    private String mVideoPath; // 待上传的视频文件路径    private int CHOOSE_CODE = 3; // 只在视频库挑选视频的请求码    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_short_take);        initView(); // 初始化视图        initCamera(); // 初始化相机    }    // 初始化视图    private void initView() {        findViewById(R.id.iv_back).setOnClickListener(v -> finish());        rl_preview = findViewById(R.id.rl_preview);        c2v_preview = findViewById(R.id.c2v_preview);        vv_content = findViewById(R.id.vv_content);        rl_record = findViewById(R.id.rl_record);        tv_cost = findViewById(R.id.tv_cost);        iv_record = findViewById(R.id.iv_record);        av_progress = findViewById(R.id.av_progress);        iv_record.setOnClickListener((v) -> dealRecord()); // 处理录像动作        findViewById(R.id.btn_album).setOnClickListener(v -> {            // 创建一个内容获取动作的意图(准备跳到系统视频库)            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 是否允许多选            intent.setType("video/*"); // 类型为视频            startActivityForResult(intent, CHOOSE_CODE); // 打开系统视频库        });        findViewById(R.id.iv_switch).setOnClickListener((v) -> {            mCameraType = (mCameraType == CameraCharacteristics.LENS_FACING_BACK) ?                    CameraCharacteristics.LENS_FACING_FRONT : CameraCharacteristics.LENS_FACING_BACK;            c2v_preview.switchCamera(mCameraType); // 切换摄像头        });        ll_next = findViewById(R.id.ll_next);        findViewById(R.id.btn_cancel).setOnClickListener(v -> finish());        findViewById(R.id.btn_next).setOnClickListener((v) -> {            // 下面跳到视频编辑界面            Intent intent = new Intent(this, ShortEditActivity.class);            intent.putExtra("video_path", mVideoPath);            startActivity(intent);        });    }    // 处理录像动作    private void dealRecord() {        if (!isRecording) {            iv_record.setImageResource(R.drawable.short_stop);            c2v_preview.startRecord(MAX_RECORD_TIME, false); // 开始录像            startRecordAnim(); // 播放录像动画            isRecording = !isRecording;        } else {            rl_record.setVisibility(View.GONE);            c2v_preview.stopRecord(); // 停止录像        }    }    // 初始化相机    private void initCamera() {        // 初始化二代相机,并指定准备就绪监听器和停止录像监听器        c2v_preview.initCamera(mCameraType, (size) -> {            int adjustHeight = Utils.getScreenWidth(this) * size.getWidth() / size.getHeight();            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) c2v_preview.getLayoutParams();            params.height = adjustHeight; // 根据预览尺寸调整预览窗口的高度            c2v_preview.setLayoutParams(params); // 设置预览视图的布局参数        }, (result) -> {            runOnUiThread(() -> {                isRecording = false;                Toast.makeText(this, result, Toast.LENGTH_SHORT).show();                mVideoPath = c2v_preview.getVideoPath();                playVideo(); // 播放视频            });        });    }    // 播放视频    private void playVideo() {        c2v_preview.closeCamera(); // 关闭相机        rl_preview.setVisibility(View.GONE);        rl_record.setVisibility(View.GONE);        vv_content.setVisibility(View.VISIBLE);        vv_content.setVideoURI(Uri.parse(mVideoPath)); // 设置视频视图的视频路径        // 设置视频视图的就绪监听器,在播放源准备完成后,命令媒体播放器循环播放视频        vv_content.setOnPreparedListener(mp -> mp.setLooping(true));        vv_content.start(); // 视频视图开始播放        ll_next.setVisibility(View.VISIBLE);    }    // 播放录像动画    private void startRecordAnim() {        tv_cost.setVisibility(View.VISIBLE);        av_progress.setVisibility(View.VISIBLE);        // 定义一个圆弧渐进动画        Animation animation = new Animation() {            private String costDesc=""; // 耗时描述            @Override            protected void applyTransformation(float interpolatedTime, Transformation t) {                String cost = String.format("%.1f秒", MAX_RECORD_TIME*interpolatedTime);                if (!costDesc.equals(cost)) { // 秒数发生变化                    costDesc = cost;                    tv_cost.setText(costDesc);                    av_progress.setAngle((int) (360*interpolatedTime)); // 设置圆弧的角度                }            }        };        animation.setDuration(MAX_RECORD_TIME*1000); // 设置动画的持续时间        tv_cost.startAnimation(animation); // 开始播放动画    }    @Override    protected void onDestroy() {        super.onDestroy();        c2v_preview.closeCamera(); // 关闭相机    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {        super.onActivityResult(requestCode, resultCode, intent);        if (resultCode==RESULT_OK && requestCode==CHOOSE_CODE) { // 从视频库回来            if (intent.getData() != null) { // 选择一个视频                Uri uri = intent.getData(); // 获得已选择视频的路径对象                // 把指定Uri的视频复制一份到内部存储空间,并返回存储路径                mVideoPath = MediaUtil.copyVideoFromUri(this, uri);                playVideo(); // 播放视频            }        }    }    private int mCurrentPosition = 0; // 当前的播放位置    @Override    protected void onResume() {        super.onResume();        // 恢复页面时立即从上次断点开始播放视频        if (!TextUtils.isEmpty(mVideoPath) && mCurrentPosition>0 && !vv_content.isPlaying()) {            vv_content.seekTo(mCurrentPosition); // 找到指定位置            vv_content.start(); // 视频视图开始播放        }    }    @Override    protected void onPause() {        super.onPause();        // 暂停页面时保存当前的播放进度        if (!TextUtils.isEmpty(mVideoPath) && vv_content.isPlaying()) { // 视频视图正在播放            // 获得视频视图当前的播放位置            mCurrentPosition = vv_content.getCurrentPosition();            vv_content.pause(); // 视频视图暂停播放        }    }}

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

来源地址:https://blog.csdn.net/jiebaoshayebuhui/article/details/128099591

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录