目录
- 相关技术 3
1.1 网络retrofit与json 3
1.2列表组件及复用机制 3
1.3 glide加载图片 3
1.4 Activity的生命周期与onSaveInstanceState 4
1.5自定义控件与属性动画 4
1.6手势检测GestureDetector 4 - 系统功能需求 5
2.1功能描述 5
2.1.1视频信息流列表显示(包含封面图) 5
2.1.2视频播放 5
2.1.3视频拍摄录制 5
2.2需求分析 6 - 系统设计与实现 6
3.1总体设计与系统组成 6
3.2模块设计与关键代码的解释 7
3.2.1网络数据获取模块 7
3.2.2循环列表模块 8
3.2.3录制视频模块 9
3.2.4视频展示模块 10
3.2.5手势识别模块 10
3.2.6爱心特效模块 11 - 系统可能的扩展 12
4.1视频上传 12
4.2 视频弹幕 12 - 总结体会 12
2.2需求分析
本系统由两个页面(Activity)构成,其中一个界面用列表展示视频信息流,包括每个视频的封面、作者昵称、描述、作者头像等相关信息。该页面还应包含一个拍摄按钮。当用户点击视频封面时,可以跳转到播放界面播放相应视频。当用户点击拍摄按钮时,APP调起系统相机录制视频,完成后返回APP,然后跳转到播放界面播放自己拍摄的视频。
另一个界面用来播放视频,当用户单击屏幕时可以控制视频的播放与暂停,当用户双击视频时,则会出现点赞爱心的动画效果。
本系统是一个简易的短视频APP,主体为视频信息流模块与视频播放模块这两大模块,在此基础上实现其它更加有趣的功能,例如在视频播放模块中实现双击视频窗口弹出点赞爱心图标的功能等等。
视频信息流列表又包含网络数据获取模块、循环列表模块、录制视频模块。其中网络数据获取模块用来从网络API中获取相应的视频信息,再传给循环列表模块。循环列表模块用来展示视频信息流,本文转载自http://www.biyezuopin.vip/onews.asp?id=15118包括视频的封面图与相应的视频信息(比如视频的作者、头像等等),并且点击相应视频封面跳转到视频播放模块自动开始播放相应视频。录制视频模块用来调起系统相机录制视频,拍摄完成后跳转到视频播放模块开始播放所拍视频,拍摄失败提示“视频录制失败”。
视频播放模块包含了视频展示模块、手势识别模块、爱心特效模块。其中视频展示模块实现视频播放功能,并将触屏事件传给手势识别模块。手势识别模块实现单击与双击事件的识别,单击控制视频的播放与暂停,双击产生点赞爱心图标。爱心特效模块实现了爱心出现、旋转、向上飞、表大变透明、最后消失的动画效果。
package com.example.finalwork;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class MainActivity extends AppCompatActivity implements MyAdapter.MyItemClickListener {
private List<Video> videos;
private ViewPager2 viewPager2;
private MyAdapter.MyItemClickListener listener;
private Context context;
private int position;
private TextView capture;
private static final int REQUEST_CODE = 233;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager2=findViewById(R.id.videoList);
capture=findViewById(R.id.nav3);
listener=this;
context=this;
if(savedInstanceState!=null){
position=savedInstanceState.getInt("position");
}else{
position=0;
}
capture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(MediaStore.ACTION_VIDEO_CAPTURE);//调起系统相机
startActivityForResult(intent,REQUEST_CODE);//等待返回结果
}
});
Retrofit retrofit=new Retrofit.Builder()//实例化Retrofit
.baseUrl("https://beiyou.bytedance.com/")
.addConverterFactory(GsonConverterFactory.create())//设置Gson的数据解析器
.build();
ApiService apiService=retrofit.create(ApiService.class);//通过Retrofit实例创建接口服务对象
//接口服务对象调用接口中的方法,获取Call对象,接着Call对象执行请求
apiService.getVideos().enqueue(new Callback<Video[]>() {
@Override
public void onResponse(Call<Video[]> call, Response<Video[]> response) {
if(response.body()!=null){
//获取数据成功时将Video数组转成Video列表,方便处理
videos = new ArrayList<Video>(Arrays.asList(response.body()));
//将Video列表传给viewpage2
viewPager2.setAdapter(new MyAdapter(videos,listener,context));
//设置viewpage2的item为之前的item
viewPager2.setCurrentItem(position,false);
}else{
Toast.makeText(MainActivity.this,"数据为空",Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<Video[]> call, Throwable t) {
Toast.makeText(MainActivity.this,t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==REQUEST_CODE&&resultCode==RESULT_OK){
//视频录制成功后跳转到播放界面进行播放
Uri uri=data.getData();
Intent intent=new Intent(this,VideoPlayer.class);
intent.putExtra("url",uri.toString());
startActivity(intent);
}else{
Toast.makeText(MainActivity.this,"视频录制失败",Toast.LENGTH_SHORT).show();
}
}
@Override
public void onItemClick(String url,int pos) {
position=pos;
Intent intent=new Intent(this,VideoPlayer.class);
intent.putExtra("url",url);
startActivity(intent);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("position",position);
}
}