一、项目中的配置
1.在项目的build的文件中添加
在repositories里添加
maven { url 'https://jitpack.io' }
在allprojects里添加
maven { url 'https://jitpack.io' }
flatDir {
dirs 'libs'
}
2.在当前module中的build文件中添加依赖
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
// 导入腾讯云直播 SDK aar
implementation(name: 'LiteAVSDK_UGC_5.0.4978', ext: 'aar')
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.35'
//glide
implementation 'com.github.bumptech.glide:glide:4.6.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
//播放器
implementation 'cn.jzvd:jiaozivideoplayer:6.2.12'
//视频缓存
implementation 'com.danikula:videocache:2.7.1'
//权限
implementation 'pub.devrel:easypermissions:1.3.0'
implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-5'
implementation 'com.android.support:recyclerview-v7:28.0.0'
需要将minSdkVersion 改成16
3.在清单文件中添加权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.Camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-feature android:name="android.hardware.camera2"/>
在mipmap-xhdpi有两张图片,是控制暂停和播放的图片
二、逻辑代码
1.MainActivity
public class MainActivity extends AppCompatActivity {
@BindView(R.id.btn_list)
Button btnList;
@BindView(R.id.btn_record)
Button btnList2;
@BindView(R.id.btn_page2)
Button btnPage2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
@OnClick({ R.id.btn_list, R.id.btn_record, R.id.btn_page2})
public void onViewClicked(View view) {
Intent intent = new Intent();
switch (view.getId()) {
case R.id.btn_list://列表页面
intent.setClass(MainActivity.this, ListActivity.class);
break;
case R.id.btn_record://录制页面
intent.setClass(MainActivity.this, RecordActivity.class);
break;
case R.id.btn_page2://翻页页面
intent.setClass(MainActivity.this, Page2Activity.class);
break;
}
startActivity(intent);
}
}
对应的xml文件
<android.support.constraint.ConstraintLayout 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=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_page2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="翻页2" />
<Button
android:id="@+id/btn_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="列表" />
<Button
android:id="@+id/btn_record"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="录制" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
2.ListActivity列表页面
public class ListActivity extends AppCompatActivity {
@BindView(R.id.rv_list)
RecyclerView rvList;
private ArrayList<String> urlList;
private ListVideoAdapter videoAdapter;
private int firstVisibleItem;
private int lastVisibleItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
ButterKnife.bind(this);
urlList = new ArrayList<>();
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201805/100651/201805181532123423.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803151735198462.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803150923220770.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803150922255785.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803150920130302.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803141625005241.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803141624378522.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803131546119319.mp4");
videoAdapter = new ListVideoAdapter(urlList);
rvList.setLayoutManager(new LinearLayoutManager(ListActivity.this));
rvList.setAdapter(videoAdapter);
addListener();
}
private void addListener() {
rvList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
lastVisibleItem = layoutManager.findLastVisibleItemPosition();
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE://停止滚动
/**在这里执行,视频的自动播放与停止*/
autoPlayVideo(recyclerView);
break;
case RecyclerView.SCROLL_STATE_DRAGGING://拖动
autoPlayVideo(recyclerView);
break;
case RecyclerView.SCROLL_STATE_SETTLING://惯性滑动
JZVideoPlayer.releaseAllVideos();
break;
}
}
});
}
/**
* 自动播放
*/
private void autoPlayVideo(RecyclerView recyclerView) {
if (firstVisibleItem == 0 && lastVisibleItem == 0 && recyclerView.getChildAt(0) != null) {
MyVideoPlayer videoView = null;
if (recyclerView != null && recyclerView.getChildAt(0) != null) {
videoView = recyclerView.getChildAt(0).findViewById(R.id.mp_video);
}
if (videoView != null) {
if (videoView.currentState == JZVideoPlayer.CURRENT_STATE_NORMAL || videoView.currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) {
videoView.startVideo();
}
}
}
for (int i = 0; i <= lastVisibleItem; i++) {
if (recyclerView == null || recyclerView.getChildAt(i) == null) {
return;
}
MyVideoPlayer
videoView = recyclerView.getChildAt(i).findViewById(R.id.mp_video);
if (videoView != null) {
Rect rect = new Rect();
//获取视图本身的可见坐标,把值传入到rect对象中
videoView.getLocalVisibleRect(rect);
//获取视频的高度
int videoHeight = videoView.getHeight();
if (rect.top <= 100 && rect.bottom >= videoHeight) {
if (videoView.currentState == JZVideoPlayer.CURRENT_STATE_NORMAL || videoView.currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) {
videoView.startVideo();
}
return;
}
JZVideoPlayer.releaseAllVideos();
} else {
JZVideoPlayer.releaseAllVideos();
}
}
}
@Override
public void onPause() {
super.onPause();
JZVideoPlayer.releaseAllVideos();
}
class ListVideoAdapter extends BaseRecAdapter<String, VideoViewHolder> {
public ListVideoAdapter(List<String> list) {
super(list);
}
@Override
public void onHolder(VideoViewHolder holder, String bean, int position) {
holder.mp_video.setUp(bean, JZVideoPlayerStandard.CURRENT_STATE_NORMAL);
if (position == 0) {
holder.mp_video.startVideo();
}
Glide.with(context).load(bean).into(holder.mp_video.thumbImageView);
holder.tv_title.setText("第" + position + "个视频");
}
@Override
public VideoViewHolder onCreateHolder() {
return new VideoViewHolder(getViewByRes(R.layout.item_video));
}
}
public class VideoViewHolder extends BaseRecViewHolder {
public View rootView;
public MyVideoPlayer mp_video;
public TextView tv_title;
public VideoViewHolder(View rootView) {
super(rootView);
this.rootView = rootView;
this.mp_video = rootView.findViewById(R.id.mp_video);
this.tv_title = rootView.findViewById(R.id.tv_title);
}
}
}
对应的xml布局
<android.support.constraint.ConstraintLayout 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=".activity.ListActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
3.RecordActivity录制页面
/**
* 录制
*/
public class RecordActivity extends AppCompatActivity implements SurfaceHolder.Callback, EasyPermissions.PermissionCallbacks {
@BindView(R.id.sv_record)
SurfaceView svRecord;
@BindView(R.id.btn_start)
Button btnStart;
@BindView(R.id.btn_end)
Button btnEnd;
@BindView(R.id.btn_switch)
Button btnSwitch;
@BindView(R.id.pb_record)
SeekBar pbRecord;
private SurfaceHolder surfaceHolder;
private Camera camera;
private MediaRecorder mediaRecorder;
//当前打开的摄像头标记 1--后,2--前
private int currentCameraType = -1;
private boolean isRecording;
private File temFile;
private MyTimer myTimer;
private static final long TIME_MAX = 15 * 1000;
private static final long TIME_INTERVAL = 500;
private static final int RC_STORAGE = 1001;
private Camera.Size size;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_record);
ButterKnife.bind(this);
initView();
}
private void initView() {
surfaceHolder = svRecord.getHolder();
surfaceHolder.addCallback(this);
//设置一些参数方便后面绘图
svRecord.setFocusable(true);
svRecord.setKeepScreenOn(true);
svRecord.setFocusableInTouchMode(true);
pbRecord.setMax(100);
pbRecord.setProgress(0);
}
@OnClick({R.id.btn_start, R.id.btn_end, R.id.btn_switch})
public void onViewClicked(View view) {
switch (view.getId()) {
//开始录制
case R.id.btn_start:
startRecord();
break;
//停止录制
case R.id.btn_end:
stopRecord(false);
break;
//切换摄像头
case R.id.btn_switch:
stopPreview();
if (currentCameraType == 1) {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
currentCameraType = 2;
btnSwitch.setText("前");
} else {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
currentCameraType = 1;
btnSwitch.setText("后");
}
startPreview();
break;
}
}
/**
* 开始录制
*/
private void startRecord() {
if (mediaRecorder == null) {
mediaRecorder = new MediaRecorder();
}
temFile = getTemFile();
try {
camera.unlock();
mediaRecorder.setCamera(camera);
//从相机采集视频
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// 从麦克采集音频信息
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
//编码格式
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoSize(size.width, size.height);
//每秒的帧数
mediaRecorder.setVideoFrameRate(24);
// 设置帧频率,然后就清晰了
mediaRecorder.setVideoEncodingBitRate(1 * 1024 * 1024 * 100);
mediaRecorder.setOutputFile(temFile.getAbsolutePath());
mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
//解决录制视频, 播放器横向问题
if (currentCameraType == 1) {
//后置
mediaRecorder.setOrientationHint(90);
} else {
//前置
mediaRecorder.setOrientationHint(270);
}
mediaRecorder.prepare();
//正式录制
mediaRecorder.start();
myTimer = new MyTimer(TIME_MAX, TIME_INTERVAL);
myTimer.start();
isRecording = true;
showtoast("开始录制");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onResume() {
super.onResume();
startPreview();
}
/**
* 获取临时文件目录
*
* @return
*/
private File getTemFile() {
String basePath = Environment.getExternalStorageDirectory().getPath() + "/doudemo/";
File baseFile = new File(basePath);
if (!baseFile.exists()) {
baseFile.mkdirs();
}
File temp = new File(basePath + System.currentTimeMillis() + ".mp4");
return temp;
}
/**
* 停止录制
*/
private void stopRecord(boolean delete) {
if (mediaRecorder == null) {
return;
}
if (myTimer != null) {
myTimer.cancel();
}
try {
mediaRecorder.stop();
} catch (Exception e) {
e.printStackTrace();
}
mediaRecorder.reset();
mediaRecorder.release();
mediaRecorder = null;
if (camera != null) {
camera.lock();
}
isRecording = false;
if (delete) {
if (temFile != null && temFile.exists()) {
temFile.delete();
}
} else {
//停止预览
stopPreview();
Intent intent = new Intent(RecordActivity.this, PrepareActivity.class);
intent.putExtra(PrepareActivity.VIDEO_PATH, temFile.getPath());
startActivity(intent);
}
showtoast("停止录制");
}
/**
* 开始预览
*/
private void startPreview() {
if (svRecord == null || surfaceHolder == null) {
return;
}
if (camera == null) {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
currentCameraType = 1;
btnSwitch.setText("后");
}
try {
camera.setPreviewDisplay(surfaceHolder);
Camera.Parameters parameters = camera.getParameters();
camera.setDisplayOrientation(90);
//实现Camera自动对焦
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes != null) {
for (String mode : focusModes) {
mode.contains("continuous-video");
parameters.setFocusMode("continuous-video");
}
}
List<Camera.Size> sizes = parameters.getSupportedVideoSizes();
if (sizes.size() > 0) {
size = sizes.get(sizes.size() - 1);
}
camera.setParameters(parameters);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 停止预览
*/
private void stopPreview() {
//停止预览并释放摄像头资源
if (camera == null) {
return;
}
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera = null;
}
@Override
protected void onStop() {
super.onStop();
stopPreview();
stopRecord(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
surfaceHolder = holder;
requestPermision();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
surfaceHolder = holder;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//停止预览并释放摄像头资源
stopPreview();
//停止录制
startRecord();
}
private void requestPermision() {
String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
if (EasyPermissions.hasPermissions(this, perms)) {
// Already have permission, do the thing
startPreview();
// ...
} else {
// Do not have permissions, request them now
EasyPermissions.requestPermissions(this, "我们的app需要以下权限",
RC_STORAGE, perms);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// Forward results to EasyPermissions
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
// Some permissions have been granted
startPreview();
}
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
// Some permissions have been denied
finish();
}
public class MyTimer extends CountDownTimer {
/**
* @param millisInFuture The number of millis in the future from the call
* to {@link #start()} until the countdown is done and {@link #onFinish()}
* is called.
* @param countDownInterval The interval along the way to receive
* {@link #onTick(long)} callbacks.
*/
public MyTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onTick(long millisUntilFinished) {
int progress = (int) ((TIME_MAX - millisUntilFinished) / (double) TIME_MAX * 100);
Log.e("cheng", "millisUntilFinished=" + progress);
pbRecord.setProgress(progress);
}
@Override
public void onFinish() {
stopRecord(false);
}
}
/**
* @param s
*/
public void showtoast(@NonNull String s) {
Toast.makeText(RecordActivity.this, s, Toast.LENGTH_SHORT).show();
}
}
对应的xml布局
<android.support.constraint.ConstraintLayout 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=".activity.RecordActivity">
<SurfaceView
android:id="@+id/sv_record"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start"
app:layout_constraintBottom_toBottomOf="parent" />
<Button
android:id="@+id/btn_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="switch"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="end"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<SeekBar
android:id="@+id/pb_record"
android:layout_width="match_parent"
android:layout_height="10dp"
android:max="100"
android:progress="0" />
</android.support.constraint.ConstraintLayout>
4.录制完后会直接进行播放,单击会进入全屏,播放完一遍后会出现暂停和播放按钮
PrepareActivity视频预览
/**
-
视频预览
*/
public class PrepareActivity extends AppCompatActivity {@BindView(R.id.mp_video)
MyVideoPlayer mpVideo;public static final String VIDEO_PATH = “VIDEO_PATH”;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_prepare);
ButterKnife.bind(this);
initView();
}private void initView() {
String path = getIntent().getStringExtra(VIDEO_PATH);
if (!TextUtils.isEmpty(path)) {
mpVideo.setUp(path, JZVideoPlayerStandard.CURRENT_STATE_NORMAL);
mpVideo.startVideo();
}
}
}
对应的xml布局
<android.support.constraint.ConstraintLayout 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=".activity.PrepareActivity">
<movie.bw.com.douyinbofang.widget.MyVideoPlayer
android:id="@+id/mp_video"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
5.Page2Activity翻页页面
/**
* 翻页2
*/
public class Page2Activity extends AppCompatActivity {
@BindView(R.id.rv_page2)
RecyclerView rvPage2;
private List<String> urlList;
private ListVideoAdapter videoAdapter;
private PagerSnapHelper snapHelper;
private LinearLayoutManager layoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_page2);
ButterKnife.bind(this);
initView();
addListener();
}
private void initView() {
urlList = new ArrayList<>();
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201811/26/09/5bfb4c55633c9.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201805/100651/201805181532123423.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803151735198462.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803150923220770.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803150922255785.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803150920130302.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803141625005241.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803141624378522.mp4");
urlList.add("http://chuangfen.oss-cn-hangzhou.aliyuncs.com/public/attachment/201803/100651/201803131546119319.mp4");
snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(rvPage2);
videoAdapter = new ListVideoAdapter(urlList);
layoutManager = new LinearLayoutManager(Page2Activity.this, LinearLayoutManager.VERTICAL, false);
rvPage2.setLayoutManager(layoutManager);
rvPage2.setAdapter(videoAdapter);
}
private void addListener() {
rvPage2.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE://停止滚动
View view = snapHelper.findSnapView(layoutManager);
JZVideoPlayer.releaseAllVideos();
RecyclerView.ViewHolder viewHolder = recyclerView.getChildViewHolder(view);
if (viewHolder != null && viewHolder instanceof VideoViewHolder) {
((VideoViewHolder) viewHolder).mp_video.startVideo();
}
break;
case RecyclerView.SCROLL_STATE_DRAGGING://拖动
break;
case RecyclerView.SCROLL_STATE_SETTLING://惯性滑动
break;
}
}
});
}
@Override
public void onPause() {
super.onPause();
JZVideoPlayer.releaseAllVideos();
}
class ListVideoAdapter extends BaseRecAdapter<String, VideoViewHolder> {
public ListVideoAdapter(List<String> list) {
super(list);
}
@Override
public void onHolder(VideoViewHolder holder, String bean, int position) {
ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
holder.mp_video.setUp(bean, JZVideoPlayerStandard.CURRENT_STATE_NORMAL);
if (position == 0) {
holder.mp_video.startVideo();
}
Glide.with(context).load(bean).into(holder.mp_video.thumbImageView);
holder.tv_title.setText("第" + position + "个视频");
}
@Override
public VideoViewHolder onCreateHolder() {
return new VideoViewHolder(getViewByRes(R.layout.item_page2));
}
}
public class VideoViewHolder extends BaseRecViewHolder {
public View rootView;
public MyVideoPlayer mp_video;
public TextView tv_title;
public VideoViewHolder(View rootView) {
super(rootView);
this.rootView = rootView;
this.mp_video = rootView.findViewById(R.id.mp_video);
this.tv_title = rootView.findViewById(R.id.tv_title);
}
}
}
对应的xml布局
<android.support.constraint.ConstraintLayout 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=".activity.Page2Activity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_page2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
三、工具类
1.BaseRecAdapter
public abstract class BaseRecAdapter<T, K extends BaseRecViewHolder> extends RecyclerView.Adapter<K> {
private List<T> list;
private onItemClickListener itemClickListener;
private OnItemLongClickListener itemLongClickListener;
public Context context;
public OnItemLongClickListener getItemLongClickListener() {
return itemLongClickListener;
}
public void setItemLongClickListener(OnItemLongClickListener itemLongClickListener) {
this.itemLongClickListener = itemLongClickListener;
}
public onItemClickListener getItemClickListener() {
return itemClickListener;
}
public void setItemClickListener(onItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
public BaseRecAdapter(List<T> list) {
this.list = list;
}
@Override
public K onCreateViewHolder(ViewGroup parent, int viewType) {
context = parent.getContext();
K holder = onCreateHolder();
//绑定listener
bindListener(holder);
return holder;
}
@Override
public void onBindViewHolder(K holder, int position) {
onHolder(holder, list.get(position), position);
}
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
/**
* 填充数据
*
* @param holder
* @param position
*/
public abstract void onHolder(K holder, T bean, int position);
public abstract K onCreateHolder();
/**
* 通过资源res获得view
*
* @param res
* @return
*/
public View getViewByRes(int res) {
return LayoutInflater.from(context).inflate(res, null);
}
/**
* 通过资源res获得view
*
* @param res
* @return
*/
public View getViewByRes(int res, ViewGroup prent) {
return LayoutInflater.from(context).inflate(res, prent);
}
/**
* 绑定事件
*
* @param holder
*/
private void bindListener(final K holder) {
if (holder == null) {
return;
}
View itemView = holder.itemView;
if (itemView == null) {
return;
}
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
itemView.setLayoutParams(params);
if (getItemClickListener() != null) {
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getItemClickListener().onItemClick(BaseRecAdapter.this, v, holder.getLayoutPosition());
}
});
}
if (getItemLongClickListener() != null) {
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return getItemLongClickListener().onItemLongClick(BaseRecAdapter.this, v, holder.getLayoutPosition());
}
});
}
}
public interface onItemClickListener {
void onItemClick(BaseRecAdapter adapter, View view, int position);
}
public interface OnItemLongClickListener {
boolean onItemLongClick(BaseRecAdapter adapter, View view, int position);
}
public void setNewData(List<T> lt) {
if (list == null) {
list = new ArrayList<T>();
}
if (lt == null) {
lt = new ArrayList<T>();
}
list = lt;
notifyDataSetChanged();
}
public List<T> getData() {
return list;
}
}
2.BaseRecViewHolder
public class BaseRecViewHolder extends RecyclerView.ViewHolder {
public BaseRecViewHolder(View itemView) {
super(itemView);
}
}
3.MyApp
需要在清单文件中关联
public class MyApp extends Application {
private HttpProxyCacheServer proxy;
public static HttpProxyCacheServer getProxy(Context context) {
MyApp app = (MyApp) context.getApplicationContext();
return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy;
}
private HttpProxyCacheServer newProxy() {
return new HttpProxyCacheServer.Builder(this)
.maxCacheSize(1024 * 1024 * 1024) // 1 Gb for cache
.fileNameGenerator(new MyFileNameGenerator())
.build();
}
@Override
public void onCreate() {
super.onCreate();
}
}
4.BaseFragment
public abstract class BaseFragment extends Fragment {
protected String TAG = getClass().getSimpleName();
protected Context context;
private View rootView;
protected abstract int getLayoutId();
protected abstract void initView();
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
//Fragment的View加载完毕的标记
private boolean isViewCreated;
//Fragment对用户可见的标记
public boolean isUIVisible;
protected boolean isLoadCompleted;
Unbinder unbinder;
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//isVisibleToUser这个boolean值表示:该Fragment的UI 用户是否可见
if (isVisibleToUser && !isLoadCompleted) {
isUIVisible = true;
lazyLoad();
} else {
isUIVisible = false;
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getUserVisibleHint() && !isLoadCompleted) {
// 此处不需要判断isViewCreated,因为这个方法在onCreateView方法之后执行
lazyLoad();
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(getLayoutId(), container, false);
unbinder = ButterKnife.bind(this, rootView);
isViewCreated = true;
initView();
return rootView;
}
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
isUIVisible = !hidden;
}
protected void lazyLoad() {
//这里进行双重标记判断,是因为setUserVisibleHint会多次回调,并且会在onCreateView执行前回调,必须确保onCreateView加载完毕且页面可见,才加载数据
if (isViewCreated && isUIVisible) {
loadData();
//数据加载完毕,恢复标记,防止重复加载
// isViewCreated = false;
// isUIVisible = false;
isLoadCompleted = true;
}
}
protected abstract void loadData();
public boolean onBackPressed() {
assert getFragmentManager() != null;
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
return true;
}
return false;
}
@Override
public void onDestroy() {
super.onDestroy();
if (unbinder != null) {
unbinder.unbind();
}
}
}
5.VideoFragment
public class VideoFragment extends BaseFragment {
@BindView(R.id.txv_video)
TXCloudVideoView txvVideo;
@BindView(R.id.rl_back_right)
RelativeLayout rlBackRight;
@BindView(R.id.dl_back_play)
DrawerLayout dlBackPlay;
@BindView(R.id.iv_play_thun)
ImageView ivPlayThun;
private TXVodPlayer mVodPlayer;
private String url;
public static final String URL = "URL";
@Override
protected int getLayoutId() {
return R.layout.fm_video;
}
@Override
protected void initView() {
url = getArguments().getString(URL);
//创建player对象
mVodPlayer = new TXVodPlayer(context);
//关键player对象与界面view
mVodPlayer.setPlayerView(txvVideo);
// url = "http://v.cctv.com/flash/mp4video6/TMS/2011/01/05/cf752b1c12ce452b3040cab2f90bc265_h264818000nero_aac32-1.mp4";
mVodPlayer.setLoop(true);
Glide.with(context)
.load(url)
.into(ivPlayThun);
// dlBackPlay.addDrawerListener(new DrawerLayout.DrawerListener() {
// @Override
// public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
//
// }
//
// @Override
// public void onDrawerOpened(@NonNull View drawerView) {
// if (mVodPlayer != null) {
// mVodPlayer.pause();
// }
// }
//
// @Override
// public void onDrawerClosed(@NonNull View drawerView) {
// if (mVodPlayer != null) {
// mVodPlayer.resume();
// }
// }
//
// @Override
// public void onDrawerStateChanged(int newState) {
//
// }
// });
//
//
// //设置菜单内容之外其他区域的背景色
// dlBackPlay.setScrimColor(Color.TRANSPARENT);
// //设置 全屏滑动
// setDrawerRightEdgeSize(getActivity(), dlBackPlay, 1);
}
@Override
protected void loadData() {
mVodPlayer.startPlay(url);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (mVodPlayer == null) {
return;
}
if (isVisibleToUser) {
mVodPlayer.resume();
} else {
mVodPlayer.pause();
}
}
@Override
public void onResume() {
super.onResume();
if (mVodPlayer != null) {
mVodPlayer.resume();
}
}
@Override
public void onPause() {
super.onPause();
if (mVodPlayer != null) {
mVodPlayer.pause();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mVodPlayer != null) {
// true代表清除最后一帧画面
mVodPlayer.stopPlay(true);
}
if (txvVideo != null) {
txvVideo.onDestroy();
}
}
/**
* 设置 全屏滑动
*
* @param activity
* @param drawerLayout
* @param displayWidthPercentage
*/
private void setDrawerRightEdgeSize(Activity activity, DrawerLayout drawerLayout, float displayWidthPercentage) {
if (activity == null || drawerLayout == null) return;
try {
// 找到 ViewDragHelper 并设置 Accessible 为true
Field mRightDragger =
drawerLayout.getClass().getDeclaredField("mRightDragger");//Right
mRightDragger.setAccessible(true);
ViewDragHelper leftDragger = (ViewDragHelper) mRightDragger.get(drawerLayout);
// 找到 edgeSizeField 并设置 Accessible 为true
Field edgeSizeField = leftDragger.getClass().getDeclaredField("mEdgeSize");
edgeSizeField.setAccessible(true);
int edgeSize = edgeSizeField.getInt(leftDragger);
// 设置新的边缘大小
Point displaySize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
edgeSizeField.setInt(leftDragger, Math.max(edgeSize, (int) (displaySize.x *
displayWidthPercentage)));
} catch (NoSuchFieldException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
}
6.MyFileNameGenerator
public class MyFileNameGenerator implements FileNameGenerator {
private static final int MAX_EXTENSION_LENGTH = 4;
@Override
public String generate(String url) {
String extension = getExtension(url);
int dotIndex = url.lastIndexOf('.');
if (url.length() > 18 && dotIndex > 18) {
return url.substring(dotIndex - 18);
}
String name = ProxyCacheUtils.computeMD5(url);
return TextUtils.isEmpty(extension) ? name : name + "." + extension;
}
private String getExtension(String url) {
int dotIndex = url.lastIndexOf('.');
int slashIndex = url.lastIndexOf('/');
return dotIndex != -1 && dotIndex > slashIndex && dotIndex + 2 + MAX_EXTENSION_LENGTH > url.length() ?
url.substring(dotIndex + 1, url.length()) : "";
}
}
7.MyVideoPlayer
public class MyVideoPlayer extends JZVideoPlayerStandard {
private RelativeLayout rl_touch_help;
private ImageView iv_start;
private LinearLayout ll_start;
private Context context;
public MyVideoPlayer(Context context) {
super(context);
this.context = context;
}
public MyVideoPlayer(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
@Override
public void onAutoCompletion() {
thumbImageView.setVisibility(View.GONE);
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
onStateAutoComplete();
setUp((String) getCurrentUrl(), JZVideoPlayer.SCREEN_WINDOW_FULLSCREEN);
} else {
super.onAutoCompletion();
setUp((String) getCurrentUrl(), JZVideoPlayer.CURRENT_STATE_NORMAL);
}
//循环播放
startVideo();
}
@Override
public void setUp(String url, int screen, Object... objects) {
if (url.startsWith("http")) {
HttpProxyCacheServer proxy = MyApp.getProxy(context);
String proxyUrl = proxy.getProxyUrl(url);
super.setUp(proxyUrl, screen, objects);
} else {
super.setUp(url, screen, objects);
}
}
@Override
public void init(final Context context) {
super.init(context);
rl_touch_help = findViewById(R.id.rl_touch_help);
ll_start = findViewById(R.id.ll_start);
iv_start = findViewById(R.id.iv_start);
resetPlayView();
rl_touch_help.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
resetPlayView();
if (isPlay()) {
fullscreenButton.performClick();
}
}
});
ll_start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (isPlay()) {
goOnPlayOnPause();
} else {
//暂停
if (currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) {
goOnPlayOnResume();
} else {
startVideo();
}
}
resetPlayView();
}
});
}
@Override
public void startVideo() {
if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
initTextureView();
addTextureView();
AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
JZUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
JZMediaManager.setDataSource(dataSourceObjects);
JZMediaManager.setCurrentDataSource(JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex));
JZMediaManager.instance().positionInList = positionInList;
onStatePreparing();
ll_start.setVisibility(VISIBLE);
} else {
super.startVideo();
ll_start.setVisibility(GONE);
}
resetPlayView();
}
@Override
public void startWindowTiny() {
}
private void resetPlayView() {
if (isPlay()) {
iv_start.setBackgroundResource(R.mipmap.video_play_parse);
} else {
iv_start.setBackgroundResource(R.mipmap.stop);
}
}
/**
* 是否播放
*
* @return
*/
private boolean isPlay() {
if (currentState == CURRENT_STATE_PREPARING || currentState == CURRENT_STATE_PLAYING || currentState == -1) {
return true;
}
return false;
}
}
四、其中的xml布局
1.fm_video.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.DrawerLayout
android:id="@+id/dl_back_play"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_play_thun"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.tencent.rtmp.ui.TXCloudVideoView
android:id="@+id/txv_video"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:id="@+id/rl_back_right"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_marginLeft="-65dp"
android:background="#fd5031"></RelativeLayout>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
2.item_page2.xml
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textSize="18sp" />
<movie.bw.com.douyinbofang.widget.MyVideoPlayer
android:id="@+id/mp_video"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
3.item_video.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textSize="18sp" />
<movie.bw.com.douyinbofang.widget.MyVideoPlayer
android:id="@+id/mp_video"
android:layout_width="match_parent"
android:layout_height="500dp" />
</LinearLayout>
4.jz_layout_standard.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:descendantFocusability="blocksDescendants">
<FrameLayout
android:id="@+id/surface_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<ImageView
android:id="@+id/thumb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="#000000"
android:scaleType="fitCenter" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone">
<LinearLayout
android:id="@+id/layout_bottom"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="@drawable/jz_bottom_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="invisible">
<TextView
android:id="@+id/current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="14dp"
android:text="00:00"
android:textColor="#ffffff" />
<SeekBar
android:id="@+id/bottom_seek_progress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1.0"
android:background="@null"
android:max="100"
android:maxHeight="1dp"
android:minHeight="1dp"
android:paddingBottom="8dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="8dp"
android:progressDrawable="@drawable/jz_bottom_seek_progress"
android:thumb="@drawable/jz_bottom_seek_thumb" />
<TextView
android:id="@+id/total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="#ffffff" />
<TextView
android:id="@+id/clarity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:paddingLeft="20dp"
android:text="clarity"
android:textAlignment="center"
android:textColor="#ffffff" />
<ImageView
android:id="@+id/fullscreen"
android:layout_width="52.5dp"
android:layout_height="fill_parent"
android:paddingLeft="14dp"
android:paddingRight="14dp"
android:scaleType="centerInside"
android:src="@drawable/jz_enlarge" />
</LinearLayout>
</LinearLayout>
<ProgressBar
android:id="@+id/bottom_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="1.5dp"
android:layout_alignParentBottom="true"
android:max="100"
android:progressDrawable="@drawable/jz_bottom_progress" />
<ImageView
android:id="@+id/back_tiny"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginLeft="6dp"
android:layout_marginTop="6dp"
android:background="@drawable/jz_click_back_tiny_selector"
android:visibility="gone" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone">
<RelativeLayout
android:id="@+id/layout_top"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="@drawable/jz_title_bg"
android:gravity="center_vertical">
<ImageView
android:id="@+id/back"
android:layout_width="23dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:paddingLeft="12dp"
android:paddingStart="12dp"
android:scaleType="centerInside"
android:src="@drawable/jz_click_back_selector" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="12dp"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_marginStart="12dp"
android:layout_toEndOf="@+id/back"
android:layout_toLeftOf="@+id/battery_time_layout"
android:layout_toRightOf="@+id/back"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#ffffff"
android:textSize="18sp" />
<LinearLayout
android:id="@+id/battery_time_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="14dp"
android:layout_marginRight="14dp"
android:gravity="center_vertical"
android:orientation="vertical">
<ImageView
android:id="@+id/battery_level"
android:layout_width="23dp"
android:layout_height="10dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/jz_battery_level_10" />
<TextView
android:id="@+id/video_current_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="#ffffffff"
android:textSize="12.0sp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
<ProgressBar
android:id="@+id/loading"
android:layout_width="@dimen/jz_start_button_w_h_normal"
android:layout_height="@dimen/jz_start_button_w_h_normal"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:indeterminateDrawable="@drawable/jz_loading"
android:visibility="invisible" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<LinearLayout
android:id="@+id/start_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/start"
android:layout_width="@dimen/jz_start_button_w_h_normal"
android:layout_height="@dimen/jz_start_button_w_h_normal"
android:src="@drawable/jz_click_play_selector" />
</LinearLayout>
<TextView
android:id="@+id/replay_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/start_layout"
android:layout_centerHorizontal="true"
android:layout_marginTop="6dp"
android:text="@string/replay"
android:textColor="#ffffff"
android:textSize="12sp"
android:visibility="invisible" />
<LinearLayout
android:id="@+id/retry_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/video_loading_faild"
android:textColor="@android:color/white"
android:textSize="14sp" />
<TextView
android:id="@+id/retry_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:background="@drawable/retry_bg"
android:paddingBottom="4dp"
android:paddingLeft="9dp"
android:paddingRight="9dp"
android:paddingTop="4dp"
android:text="@string/click_to_restart"
android:textColor="@android:color/white"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/rl_touch_help"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0"
android:background="#f0f2f7"></RelativeLayout>
<LinearLayout
android:id="@+id/ll_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:padding="15dp"
android:visibility="gone">
<ImageView
android:id="@+id/iv_start"
android:layout_width="16dp"
android:layout_height="18dp"
android:background="@mipmap/stop" />
</LinearLayout>
</RelativeLayout>
这里面有自定义的东西,所以要改变路径名