首先先放一张最简单的视频播放图:
OK,加下来开始进入正题:
一、开始集成(GitHub地址)
1.导入依赖:
//娇子播放器
//项目地址 : https://github.com/lipangit/JiaoZiVideoPlayer
implementation 'cn.jzvd:jiaozivideoplayer:7.0.5'
2.添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
3.添加控件
ps:这里有一点需要注意,通常来说我们去添加一个控件的时候都是直接添加控件到对应布局,就像这样:
<?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=".activity.JiaoZiVideo.JZInActivity">
<!-- 原生娇子播放器 -->
<cn.jzvd.JzvdStd
android:id="@+id/jzin_video"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>
但是这样做之后,实际测试中的效果是,初始进来加载布局没问题,正常显示,但是进入全屏之后再退出全屏的时候,效果是这样的:
正确的做法是:在视频控件的外层在添加一层布局,将宽高写在父布局里,就像这样:
<?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=".activity.JiaoZiVideo.JZInActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp">
<!-- 原生娇子播放器 -->
<cn.jzvd.JzvdStd
android:id="@+id/jzin_video"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
具体是什么原因导致的这个问题目前暂无法得知,待研究....
4.设置视频地址和标题
官方文档中推荐使用的是 Glide 进行加载视频缩略图,因为我这里目前用的是Fresco,所以暂时就不写了,后期再补出来~
private JzvdStd jzin_video;
private void initView() {
jzin_video = (JzvdStd) findViewById(R.id.jzin_video);
//加载网络视频
jzin_video.setUp("https://img.tukuppt.com/video_show/2402760/00/01/73/5b495ddab7660.mp4","网络视频测试");
//加载视频缩略图
//待完善代码
}
5.生命周期中添加基本监听
@Override
protected void onPause() {
super.onPause();
jzin_video.releaseAllVideos();
}
@Override
public void onBackPressed() {
if (jzin_video.backPress()) {
return;
}
super.onBackPressed();
}
6.在 AndroidManifest.xml 中对应的Activity添加:
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait"
以上基本上就完成了娇子播放器的简单播放网络视频,项目中原先用的是百度播放器,对比之下娇子有很强的的优势,更加易用.
二、在列表中播放
注意,每个有视频播放的页面,只要需要全屏,其对应的 Activity 都应在 AndroidManifest.xml 中添加参数
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait"
在此引用的是 RecycleView 作为列表
1.创建列表布局
<?xml version="1.0" encoding="utf-8"?>
<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.JiaoZiVideo.JZInListActivity">
<!-- 承载视频的列表 -->
<android.support.v7.widget.RecyclerView
android:id="@+id/jzinList_Rec"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>
2.创建条目布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="100dp">
<!-- 顶部标题 -->
<TextView
android:id="@+id/item_listitem_title_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:textSize="16sp"
android:textColor="#383838"
android:textStyle="normal"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"/>
<!-- 条目中视频布局 -->
<RelativeLayout
android:id="@+id/item_listitem_videoLayout"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:layout_below="@id/item_listitem_title_txt"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp">
<!-- 原生娇子播放器 -->
<cn.jzvd.JzvdStd
android:id="@+id/jzin_video_inRecList"
android:layout_width="match_parent"
android:layout_height="200dp" />
</RelativeLayout>
<!-- 来源布局 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/item_listitem_videoLayout"
android:layout_marginBottom="5dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp">
<!-- 小眼睛图标 -->
<ImageView
android:id="@+id/item_listitem_readingVolume_img"
android:layout_centerVertical="true"
android:layout_width="15dp"
android:layout_height="10dp"
android:src="@mipmap/readingvolume"/>
<!-- 阅读量 -->
<TextView
android:id="@+id/item_listitem_readingVolume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/item_listitem_readingVolume_img"
android:textColor="#999999"
android:textSize="10sp" />
<!-- 来源 -->
<TextView
android:id="@+id/item_listitem_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:textColor="#999999"
android:textSize="10sp"
android:maxEms="8"
android:maxLines="1"
android:ellipsize="end"
android:layout_marginLeft="10dp"/>
<!-- 时间 -->
<TextView
android:id="@+id/item_listitem_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/item_listitem_readingVolume"
android:layout_toLeftOf="@id/item_listitem_source"
android:layout_marginLeft="8dp"
android:layout_centerVertical="true"
android:textColor="#999999"
android:textSize="10sp" />
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
3.编写适配器
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.wwgtest.goodlib.R;
import java.util.List;
import java.util.Map;
import cn.jzvd.Jzvd;
import cn.jzvd.JzvdStd;
/**
* 作者:WWGsky on 2019/7/16 18:00
* <p>
* 作用: 娇子列表播放适配器
*/
public class JZInRecAdapter extends RecyclerView.Adapter<JZInRecAdapter.LinearViewHolder>{
private Context mContext;
private List<Map<String,String>> list;
private OnItemClickListener itemClickListener;
public JZInRecAdapter(Context mContext, List<Map<String,String>> data) {
this.mContext = mContext;
list = data;
}
@Override
public JZInRecAdapter.LinearViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LinearViewHolder holder = new LinearViewHolder(LayoutInflater.from(
mContext).inflate(R.layout.item_jzinlist_itemlayout, parent,
false));
return holder;
}
@Override
public void onBindViewHolder(JZInRecAdapter.LinearViewHolder holder, int position) {
//给控件赋值
holder.item_listitem_title_txt.setText(list.get(position).get("title"));
//在此加载视频链接
//第一个参数是视频连接地址,第二个为标题,第三个为播放器格式,当前为标准模式
holder.jzin_video.setUp(list.get(position).get("videoUel"),"", Jzvd.SCREEN_NORMAL);
holder.item_listitem_readingVolume.setText(list.get(position).get("readingVolume"));
holder.item_listitem_source.setText(list.get(position).get("source"));
holder.item_listitem_time.setText(list.get(position).get("time"));
//在此预设了条目的点击监听
if (itemClickListener!=null){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
itemClickListener.onItemClick(position);
}
});
}
}
@Override
public int getItemCount() {
return list.size();
}
class LinearViewHolder extends RecyclerView.ViewHolder{
private TextView item_listitem_title_txt;
private JzvdStd jzin_video;
private final TextView item_listitem_readingVolume;
private final TextView item_listitem_source;
private final TextView item_listitem_time;
public LinearViewHolder(View itemView){
super(itemView);
item_listitem_title_txt=(TextView) itemView.findViewById(R.id.item_listitem_title_txt);
jzin_video = (JzvdStd) itemView.findViewById(R.id.jzin_video_inRecList);
item_listitem_readingVolume = (TextView) itemView.findViewById(R.id.item_listitem_readingVolume);
item_listitem_source = (TextView) itemView.findViewById(R.id.item_listitem_source);
item_listitem_time = (TextView) itemView.findViewById(R.id.item_listitem_time);
}
}
/**
* 条目点击监听接口
*/
public interface OnItemClickListener {
void onItemClick(int position);
}
/**
* 暴露给外部的条目点击监听方法
*/
public void setOnItemClickListener(OnItemClickListener listener) {
itemClickListener = listener;
}
}
4.准备测试数据
Map<String,String> map1 = new HashMap<>();
map1.put("title","多彩LED酷炫旋转视频背景");
map1.put("videoUel","https://img.tukuppt.com/video_show/2402760/00/01/73/5b495ddab7660.mp4");
map1.put("readingVolume","16485");
map1.put("source","熊猫");
map1.put("time","1小时前");
Map<String,String> map2 = new HashMap<>();
map2.put("title","线条描绘时间线同学会毕业相册");
map2.put("videoUel","https://img.tukuppt.com/video_show/2629112/00/02/76/5b8ce0b65a774.mp4");
map2.put("readingVolume","16485");
map2.put("source","熊猫");
map2.put("time","5小时前");
Map<String,String> map3 = new HashMap<>();
map3.put("title","大气水墨转场照片相册");
map3.put("videoUel","https://img.tukuppt.com/video_show/2629112/00/03/29/5bc1fe8d802b6.mp4");
map3.put("readingVolume","16485");
map3.put("source","熊猫");
map3.put("time","刚刚");
Map<String,String> map4 = new HashMap<>();
map4.put("title","震撼年会开场片头");
map4.put("videoUel","https://img.tukuppt.com/video_show/2405811/00/02/45/5b65b4da72f5c.mp4");
map4.put("readingVolume","16485");
map4.put("source","熊猫");
map4.put("time","一天前");
5.将数据设置到List
jzinList_Rec = (RecyclerView) findViewById(R.id.jzinList_Rec);
//设置线性布局
jzinList_Rec.setLayoutManager(new LinearLayoutManager(this));
//创建测试数据源
List<Map<String,String>> list = new ArrayList<>();
//添加测试数据
list.add(map1);
list.add(map2);
list.add(map3);
list.add(map4);
//创建适配器对象
jzInRecAdapter = new JZInRecAdapter(this, list);
//设置适配器
jzinList_Rec.setAdapter(jzInRecAdapter);
6.添加条目复用监听
//添加条目复用监听
jzinList_Rec.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
}
@Override
public void onChildViewDetachedFromWindow(View view) {
Jzvd jzvd = view.findViewById(R.id.jzin_video_inRecList);
if (jzvd != null && Jzvd.CURRENT_JZVD != null &&
jzvd.jzDataSource.containsTheUrl(Jzvd.CURRENT_JZVD.jzDataSource.getCurrentUrl())) {
if (Jzvd.CURRENT_JZVD != null && Jzvd.CURRENT_JZVD.screen != Jzvd.SCREEN_FULLSCREEN) {
Jzvd.releaseAllVideos();
}
}
}
});
7.添加基本生命周期监听
@Override
public void onBackPressed() {
if (Jzvd.backPress()) {
return;
}
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
Jzvd.releaseAllVideos();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
}
return super.onOptionsItemSelected(item);
}
完整 Activity :
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.MenuItem;
import android.view.View;
import com.wwgtest.goodlib.R;
import com.wwgtest.goodlib.adapter.JZInRecAdapter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cn.jzvd.Jzvd;
/**
* 娇子播放器-在列表中展示
*/
public class JZInListActivity extends AppCompatActivity {
private RecyclerView jzinList_Rec;
private JZInRecAdapter jzInRecAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_jzin_list);
initView();
}
private void initView() {
jzinList_Rec = (RecyclerView) findViewById(R.id.jzinList_Rec);
//设置线性布局
jzinList_Rec.setLayoutManager(new LinearLayoutManager(this));
//创建测试数据源
List<Map<String,String>> list = new ArrayList<>();
Map<String,String> map1 = new HashMap<>();
map1.put("title","多彩LED酷炫旋转视频背景");
map1.put("videoUel","https://img.tukuppt.com/video_show/2402760/00/01/73/5b495ddab7660.mp4");
map1.put("readingVolume","16485");
map1.put("source","熊猫");
map1.put("time","1小时前");
Map<String,String> map2 = new HashMap<>();
map2.put("title","线条描绘时间线同学会毕业相册");
map2.put("videoUel","https://img.tukuppt.com/video_show/2629112/00/02/76/5b8ce0b65a774.mp4");
map2.put("readingVolume","16485");
map2.put("source","熊猫");
map2.put("time","5小时前");
Map<String,String> map3 = new HashMap<>();
map3.put("title","大气水墨转场照片相册");
map3.put("videoUel","https://img.tukuppt.com/video_show/2629112/00/03/29/5bc1fe8d802b6.mp4");
map3.put("readingVolume","16485");
map3.put("source","熊猫");
map3.put("time","刚刚");
Map<String,String> map4 = new HashMap<>();
map4.put("title","震撼年会开场片头");
map4.put("videoUel","https://img.tukuppt.com/video_show/2405811/00/02/45/5b65b4da72f5c.mp4");
map4.put("readingVolume","16485");
map4.put("source","熊猫");
map4.put("time","一天前");
//添加测试数据
list.add(map1);
list.add(map2);
list.add(map3);
list.add(map4);
//创建适配器对象
jzInRecAdapter = new JZInRecAdapter(this, list);
//设置适配器
jzinList_Rec.setAdapter(jzInRecAdapter);
//添加条目复用监听
jzinList_Rec.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
}
@Override
public void onChildViewDetachedFromWindow(View view) {
Jzvd jzvd = view.findViewById(R.id.jzin_video_inRecList);
if (jzvd != null && Jzvd.CURRENT_JZVD != null &&
jzvd.jzDataSource.containsTheUrl(Jzvd.CURRENT_JZVD.jzDataSource.getCurrentUrl())) {
if (Jzvd.CURRENT_JZVD != null && Jzvd.CURRENT_JZVD.screen != Jzvd.SCREEN_FULLSCREEN) {
Jzvd.releaseAllVideos();
}
}
}
});
}
@Override
public void onBackPressed() {
if (Jzvd.backPress()) {
return;
}
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
Jzvd.releaseAllVideos();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
}
return super.onOptionsItemSelected(item);
}
}
三、圆角播放器
四、自定义UI