这个功能做了好久了,今天总结下,也不是复杂的功能,记录一下以后有需要就不用再写一遍了,还有很多可以优化的地方。
需要Dotween插件。
注意:父级不要有布局组开启,可能会影响视频播放
层次结构:和每个组件,下面这个不是全屏,所以加了Mask。
RawImage1和RawImage2放在你想展示的位置的左边(往右滑)或右边(往左滑)
下面的两个图片元素,添加VideoPlayer,如果确定是图片和视频混播两个VP上放同一个RenderTexture即可,如果有可能全是视频,则每一个上添加一个RenderTexture.
最后添加这个脚本:ImageAndVideoLoopPlay,放在哪都行,只需把暴露的Fist、Second图设置了,还有RenderTexture,其他参数代码里会说明。
更新:增加了轮播模式
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;
using System.Collections;
using System.IO;
public enum PlayMode
{
OnePictureByOneVideo = 1, //一张图片一个视频
OnePictureClassByOneVideoClass = 2, //先图片再视频,顺序也可以改
FileOrder = 3, //文件顺序
}
/// <summary>
/// 图片视频轮播
/// 注:全屏显示图片和视频
/// </summary>
public class ImgAndVideoLoopPlay : MonoBehaviour
{
public Transform first;
public Transform second;
public float duration = 0.5f;
public Ease ease = Ease.Linear;
public double imageIntervalTime = 5;
public double videoIntervalTime = 10;
public bool isOpenScreen;
public bool isMoveLeft = true;
public PlayMode mode = PlayMode.FileOrder;
[HideInInspector]
public float originalPos;
private double intervalTime = 1;
private Transform currentMoveTF;
private Transform willResetTF;
private int pictureCurrentIndex;
private int videoCurrentIndex;
private int fileCurrentIndex;
private float maxWidth;
private float maxHeight;
/// <summary>
/// 下一个是否显示视频屏保
/// </summary>
private bool nextIsVideo;
private LoadResource loadResource;
private void Awake()
{
loadResource = GetComponent<LoadResource>();
}
void Start()
{
mode = ConfigMode.mode;
currentMoveTF = second;
willResetTF = first;
RectTransform rect = first as RectTransform;
maxHeight = rect.rect.height;
maxWidth = rect.rect.width;
originalPos = second.localPosition.x;
switch (mode)
{
case PlayMode.OnePictureByOneVideo:
case PlayMode.OnePictureClassByOneVideoClass:
nextIsVideo = false; //改这里:控制先播放哪种类型,默认图片
break;
case PlayMode.FileOrder:
if (loadResource.IsVideo(fileCurrentIndex))
nextIsVideo = true;
else
nextIsVideo = false;
break;
}
}
float time;
void Update()
{
if (loadResource.videoNum > 0 || loadResource.loadedPictureNum > 0 && loadResource.IsAllPictureLoadCompleted)
{
if (isOpenScreen)
{
time += Time.deltaTime;
if (time > intervalTime)
{
time = 0;
//图片视频轮播
PlayPicturesAndVideos();
}
}
}
}
/// <summary>
/// 图片视频轮播,默认往左,一张图片,一个视频
/// </summary>
/// <param name="isMoveLeft">默认往左移动</param>
private void PlayPicturesAndVideos()
{
if (loadResource.videosPathList.Count == 0 && loadResource.totalImgFiles.Count == 0)
{
Debug.LogError("没有图片和视频资源,屏保显示默认");
return;
}
if (loadResource.totalImgFiles.Count != 0 && loadResource.picturesList.Count == 0)
{
Debug.Log("图片正则加载,请稍等!");
return;
}
if (loadResource.videosPathList.Count == 0)
{
nextIsVideo = false;
}
else if (loadResource.totalImgFiles.Count == 0)
{
nextIsVideo = true;
}
if (isMoveLeft)//左移
{
currentMoveTF.localPosition = new Vector3(originalPos, currentMoveTF.localPosition.y, currentMoveTF.localPosition.z);
//图片视频轮播
if (nextIsVideo)
{
switch (mode)
{
case PlayMode.OnePictureByOneVideo:
nextIsVideo = false;
break;
case PlayMode.OnePictureClassByOneVideoClass:
JudgeVideo();
break;
case PlayMode.FileOrder:
JudgeIsVideo();
break;
}
//设置视频
SetVideo();
}
else
{
switch (mode)
{
case PlayMode.OnePictureByOneVideo:
nextIsVideo = true;
break;
case PlayMode.OnePictureClassByOneVideoClass:
JudgePicture();
break;
case PlayMode.FileOrder:
JudgeIsVideo();
break;
}
//设置图片
SetPicture();
}
}
else//右移
{
currentMoveTF.localPosition = new Vector3(-originalPos, currentMoveTF.localPosition.y, currentMoveTF.localPosition.z);
if (nextIsVideo)
{
switch (mode)
{
case PlayMode.OnePictureByOneVideo:
nextIsVideo = false;
break;
case PlayMode.OnePictureClassByOneVideoClass:
JudgeVideo();
break;
case PlayMode.FileOrder:
JudgeIsVideo();
break;
}
//设置视频
SetVideo();
}
else
{
switch (mode)
{
case PlayMode.OnePictureByOneVideo:
nextIsVideo = true;
break;
case PlayMode.OnePictureClassByOneVideoClass:
JudgePicture();
break;
case PlayMode.FileOrder:
JudgeIsVideo();
break;
}
//设置图片
SetPicture();
}
}
currentMoveTF.DOLocalMoveX(0, duration).SetEase(ease).OnComplete(() =>
{
willResetTF.localPosition = new Vector3(originalPos, willResetTF.localPosition.y, willResetTF.localPosition.z);
willResetTF.SetAsLastSibling();
Transform temp = currentMoveTF;
currentMoveTF = willResetTF;
willResetTF = temp;
});
}
//Judge Picture
private void JudgePicture()
{
if (loadResource.picturesList.Count != 0 && loadResource.videosPathList.Count != 0)
{
if (pictureCurrentIndex == loadResource.picturesList.Count - 1)
nextIsVideo = true;
else
nextIsVideo = false;
}
}
//Judge Video
private void JudgeVideo()
{
if (loadResource.picturesList.Count != 0 && loadResource.videosPathList.Count != 0)
{
if (videoCurrentIndex == loadResource.videosPathList.Count - 1)
nextIsVideo = false;
else
nextIsVideo = true;
}
}
//Judge Is Video
private void JudgeIsVideo()
{
fileCurrentIndex = (fileCurrentIndex + 1) % loadResource.allFile.Count;
if (loadResource.IsVideo(fileCurrentIndex))
nextIsVideo = true;
else
nextIsVideo = false;
}
/// <summary>
/// 设置图片
/// </summary>
private void SetPicture()
{
Texture2D tex = loadResource.picturesList[pictureCurrentIndex].tex;
RawImage raw = currentMoveTF.GetComponentInChildren<RawImage>();
raw.texture = tex;
intervalTime = imageIntervalTime;
pictureCurrentIndex = (pictureCurrentIndex + 1) % loadResource.picturesList.Count;
}
/// <summary>
/// 设置视频
/// </summary>
private void SetVideo()
{
VideoPlayer vp = currentMoveTF.GetComponentInChildren<VideoPlayer>();
currentMoveTF.GetComponentInChildren<RawImage>().texture = vp.targetTexture;
vp.url = loadResource.videosPathList[videoCurrentIndex];
vp.SetDirectAudioMute(0, false);
vp.Play();
RectTransform rect = vp.transform as RectTransform;
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, maxWidth);
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, maxHeight);
intervalTime = videoIntervalTime;
StartCoroutine(SetVideoIntervalTime(vp));
videoCurrentIndex = (videoCurrentIndex + 1) % loadResource.videosPathList.Count;
}
/// <summary>
/// 设置视频间隔:播放URL视频,不能立刻获取到视频时长,需要播放一段时间
/// </summary>
/// <param name="vp">视频</param>
/// <returns></returns>
private IEnumerator SetVideoIntervalTime(VideoPlayer vp)
{
for (int i = 0; i < 10; i++)
{
yield return new WaitForSeconds(0.5f);
if (vp.length > 0)
{
intervalTime = vp.length;
yield break;
}
}
}
public void MuteVideo(bool isMute)
{
VideoPlayer vp = currentMoveTF.GetComponentInChildren<VideoPlayer>();
vp.SetDirectAudioMute(0, isMute);
vp = willResetTF.GetComponentInChildren<VideoPlayer>();
vp.SetDirectAudioMute(0, isMute);
}
public void CancelMuteCurrent()
{
VideoPlayer vp = currentMoveTF.GetComponentInChildren<VideoPlayer>();
vp.SetDirectAudioMute(0, true);
vp = willResetTF.GetComponentInChildren<VideoPlayer>();
var raw = willResetTF.GetComponent<RawImage>();
if (raw.texture == vp.targetTexture)
{
vp.SetDirectAudioMute(0, false);
}
else
{
vp.SetDirectAudioMute(0, true);
}
}
}
class ConfigMode
{
public static PlayMode mode = PlayMode.FileOrder;
static ConfigMode()
{
string path = Application.streamingAssetsPath + "/ModeConfig.txt";
if (File.Exists(path))
{
var str = File.ReadAllText(path).Trim();
mode = (PlayMode)int.Parse(str.Split('=')[1]);
}
else
{
File.WriteAllText(path, $"轮播模式={(int)mode}");
}
}
}
还需要一个资源加载的脚本:如果不是加载的外部图片,可以不用,代码自己修改。
这个脚本挂哪都行,可以和上面的放一块。
using System;
using System.IO;
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using System.Collections.Generic;
using System.Text.RegularExpressions;
/// <summary>
/// 图片数据
/// </summary>
public class PictureData
{
public string name;
public Texture2D tex;
}
/// <summary>
/// 加载资源
/// </summary>
public class LoadResource : MonoBehaviour
{
public string resourcePath = "/ImagesAndVideos/";
public List<PictureData> picturesList;
public List<string> totalImgFiles;
public int loadedPictureNum
{
get
{
return picturesList.Count;
}
}
public List<string> videosPathList;
public int videoNum
{
get
{
return videosPathList.Count;
}
}
public List<string> allFile;
public Action FirstPictureLoadCompleted;
Regex reg = new Regex("^[0-9]+");
private void Awake()
{
resourcePath = Application.streamingAssetsPath + resourcePath;
if (!Directory.Exists(resourcePath))
Directory.CreateDirectory(resourcePath);
allFile = new List<string>();
totalImgFiles = new List<string>();
picturesList = new List<PictureData>();
videosPathList = new List<string>();
//获取图片并加载
StartCoroutine(GetPictures());
//获取视频路径
GetVideoPath();
}
/// <summary>
/// 获取视频路径
/// </summary>
private void GetVideoPath()
{
string[] videos = Directory.GetFiles(resourcePath, "*.mp4");
Debug.Log("本地视频数量:" + videos.Length);
videosPathList.AddRange(videos);
SortList(videosPathList);
allFile.AddRange(videosPathList);
SortList(allFile);
}
/// <summary>
/// 获取图片
/// </summary>
/// <returns></returns>
private IEnumerator GetPictures()
{
string[] jpgs = Directory.GetFiles(resourcePath, "*.jpg");
string[] pngs = Directory.GetFiles(resourcePath, "*.png");
totalImgFiles.AddRange(pngs);
totalImgFiles.AddRange(jpgs);
SortList(totalImgFiles);
allFile.AddRange(totalImgFiles);
Debug.Log("本地图片数量:" + totalImgFiles.Count);
for (int i = 0; i < totalImgFiles.Count; i++)
{
yield return StartCoroutine(LoadPicuture(totalImgFiles[i]));
FirstPictureLoadCompleted?.Invoke();
FirstPictureLoadCompleted = null;
}
}
/// <summary>
/// 加载图片
/// </summary>
/// <param name="filePath">图片路径</param>
/// <returns></returns>
private IEnumerator LoadPicuture(string filePath)
{
UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(filePath);
yield return uwr.SendWebRequest();
if (uwr.downloadHandler.isDone)
{
string fileName = Path.GetFileNameWithoutExtension(filePath);
var temp = reg.Replace(fileName, "");
Texture2D fileTex = DownloadHandlerTexture.GetContent(uwr);
picturesList.Add(new PictureData() { name = temp, tex = fileTex });
}
}
public bool IsAllPictureLoadCompleted
{
get
{
return loadedPictureNum > 0 && loadedPictureNum == picturesList.Count;
}
}
/// <summary>
/// is video
/// </summary>
/// <param name="index">索引</param>
/// <returns></returns>
public bool IsVideo(int index)
{
if (index >= allFile.Count)
{
Debug.LogError("索引超出!");
return false;
}
return Path.GetExtension(allFile[index]) == ".mp4";
}
private void SortList(List<string> list)
{
list.Sort((f1, f2) =>
{
var fileName1 = Path.GetFileNameWithoutExtension(f1);
var fileName2 = Path.GetFileNameWithoutExtension(f2);
var temp1 = reg.Match(fileName1).Value;
var temp2 = reg.Match(fileName2).Value;
if (string.IsNullOrEmpty(temp1) || string.IsNullOrEmpty(temp2))
{
return fileName1.CompareTo(fileName2);
}
var num1 = int.Parse(temp1);
var num2 = int.Parse(temp2);
return num1.CompareTo(num2);
});
}
}