419 lines
11 KiB
C#
419 lines
11 KiB
C#
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
/// <summary>
|
||
/// 自动图片轮播器
|
||
/// 支持从本地文件夹加载图片并自动切换
|
||
/// </summary>
|
||
public class AutoImageSlider : MonoBehaviour
|
||
{
|
||
[Header("UI组件")]
|
||
public Image displayImage; // 显示图片的Image组件
|
||
// 记录原始宽高
|
||
private float originWidth;
|
||
private float originHeight;
|
||
public RectTransform panelRectTransform; // 图片容器的RectTransform
|
||
public Text infoText; // 显示信息的文本组件(可选)
|
||
|
||
[Header("路径配置")]
|
||
[Tooltip("图片所在的文件夹路径,相对于StreamingAssets文件夹")]
|
||
public string imageFolderPath = "Images";
|
||
|
||
[Header("轮播设置")]
|
||
[Tooltip("每张图片显示的时间(秒)")]
|
||
public float slideInterval = 3f;
|
||
[Tooltip("是否自动播放")]
|
||
public bool autoPlay = true;
|
||
[Tooltip("是否循环播放")]
|
||
public bool loop = true;
|
||
[Tooltip("图片切换时的淡入淡出时间")]
|
||
public float fadeDuration = 0.5f;
|
||
|
||
[Header("手动控制")]
|
||
[Tooltip("上一张按钮")]
|
||
public Button prevButton;
|
||
[Tooltip("下一张按钮")]
|
||
public Button nextButton;
|
||
[Tooltip("播放/暂停按钮")]
|
||
public Button playPauseButton;
|
||
|
||
// 内部变量
|
||
private List<Texture2D> loadedTextures = new List<Texture2D>();
|
||
private List<Sprite> loadedSprites = new List<Sprite>();
|
||
private int currentImageIndex = 0;
|
||
private Coroutine slideCoroutine;
|
||
public bool isPlaying = false;
|
||
void Awake()
|
||
{
|
||
originWidth = displayImage.rectTransform.sizeDelta.x;
|
||
originHeight = displayImage.rectTransform.sizeDelta.y;
|
||
}
|
||
void Start()
|
||
{
|
||
|
||
InitializeSlider();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化轮播器
|
||
/// </summary>
|
||
private async void InitializeSlider()
|
||
{
|
||
|
||
LoadImagesFromFolder();
|
||
await Task.Delay(1000);
|
||
if (loadedSprites.Count > 0)
|
||
{
|
||
ShowImageAtIndex(currentImageIndex);
|
||
SetupButtons();
|
||
|
||
if (autoPlay)
|
||
{
|
||
Play();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("未找到任何图片文件,请检查路径: " + GetFullImagePath());
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从文件夹加载图片
|
||
/// </summary>
|
||
private void LoadImagesFromFolder()
|
||
{
|
||
loadedTextures.Clear();
|
||
loadedSprites.Clear();
|
||
|
||
string fullPath = Path.Combine(Application.streamingAssetsPath, imageFolderPath);
|
||
|
||
if (!Directory.Exists(fullPath))
|
||
{
|
||
Debug.LogError("图片文件夹不存在: " + fullPath);
|
||
return;
|
||
}
|
||
|
||
// 支持的图片格式
|
||
string[] imageExtensions = { "*.png", "*.jpg", "*.jpeg", "*.gif", "*.bmp", "*.tga" };
|
||
foreach (string extension in imageExtensions)
|
||
{
|
||
string[] files = Directory.GetFiles(fullPath, extension);
|
||
|
||
foreach (string filePath in files)
|
||
{
|
||
StartCoroutine(LoadImageAtPath(filePath));
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在指定路径加载图片
|
||
/// </summary>
|
||
/// <param name="filePath">图片文件路径</param>
|
||
private IEnumerator LoadImageAtPath(string filePath)
|
||
{
|
||
string url = "file://" + filePath;
|
||
|
||
using (WWW www = new WWW(url))
|
||
{
|
||
yield return www;
|
||
|
||
if (!string.IsNullOrEmpty(www.error))
|
||
{
|
||
Debug.LogError("加载图片失败: " + www.error + " - " + filePath);
|
||
}
|
||
else
|
||
{
|
||
Texture2D texture = www.texture;
|
||
if (texture != null)
|
||
{
|
||
loadedTextures.Add(texture);
|
||
|
||
// 创建精灵
|
||
Sprite sprite = Sprite.Create(
|
||
texture,
|
||
new Rect(0, 0, texture.width, texture.height),
|
||
new Vector2(0.5f, 0.5f)
|
||
);
|
||
sprite.name = Path.GetFileNameWithoutExtension(filePath);
|
||
loadedSprites.Add(sprite);
|
||
// 更新UI信息
|
||
UpdateInfoText();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示指定索引的图片
|
||
/// </summary>
|
||
/// <param name="index">图片索引</param>
|
||
private void ShowImageAtIndex(int index)
|
||
{
|
||
if (loadedSprites.Count == 0) return;
|
||
|
||
// 确保索引在有效范围内
|
||
if (index < 0) index = loadedSprites.Count - 1;
|
||
if (index >= loadedSprites.Count) index = 0;
|
||
|
||
currentImageIndex = index;
|
||
|
||
if (displayImage != null && loadedSprites[currentImageIndex] != null)
|
||
{
|
||
// 应用淡入淡出效果
|
||
StartCoroutine(FadeImage(displayImage, loadedSprites[currentImageIndex]));
|
||
}
|
||
|
||
UpdateInfoText();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 淡入淡出图片切换效果
|
||
/// </summary>
|
||
/// <param name="image">目标Image组件</param>
|
||
/// <param name="newSprite">新精灵</param>
|
||
private IEnumerator FadeImage(Image image, Sprite newSprite)
|
||
{
|
||
if (fadeDuration <= 0)
|
||
{
|
||
image.sprite = newSprite;
|
||
//image.SetNativeSize();
|
||
//image.rectTransform.sizeDelta = new Vector2(originWidth, originHeight);
|
||
yield break;
|
||
}
|
||
|
||
// 淡出
|
||
Color originalColor = image.color;
|
||
float elapsedTime = 0;
|
||
while (elapsedTime < fadeDuration / 2)
|
||
{
|
||
image.color = new Color(originalColor.r, originalColor.g, originalColor.b, 1 - (elapsedTime / (fadeDuration / 2)));
|
||
elapsedTime += Time.deltaTime;
|
||
yield return null;
|
||
}
|
||
|
||
// 设置新图片
|
||
image.sprite = newSprite;
|
||
//image.SetNativeSize();
|
||
|
||
// 淡入
|
||
elapsedTime = 0;
|
||
while (elapsedTime < fadeDuration / 2)
|
||
{
|
||
image.color = new Color(originalColor.r, originalColor.g, originalColor.b, elapsedTime / (fadeDuration / 2));
|
||
elapsedTime += Time.deltaTime;
|
||
yield return null;
|
||
}
|
||
|
||
image.color = originalColor;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 下一张图片
|
||
/// </summary>
|
||
public void NextImage()
|
||
{
|
||
if (loadedSprites.Count == 0) return;
|
||
|
||
int nextIndex = currentImageIndex + 1;
|
||
if (nextIndex >= loadedSprites.Count)
|
||
{
|
||
nextIndex = loop ? 0 : currentImageIndex; // 如果不循环则停留在最后一张
|
||
}
|
||
|
||
ShowImageAtIndex(nextIndex);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 上一张图片
|
||
/// </summary>
|
||
public void PreviousImage()
|
||
{
|
||
if (loadedSprites.Count == 0) return;
|
||
|
||
int prevIndex = currentImageIndex - 1;
|
||
if (prevIndex < 0)
|
||
{
|
||
prevIndex = loop ? loadedSprites.Count - 1 : 0; // 如果不循环则停留在第一张
|
||
}
|
||
|
||
ShowImageAtIndex(prevIndex);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开始播放
|
||
/// </summary>
|
||
public void Play()
|
||
{
|
||
if (isPlaying) return;
|
||
transform.parent.gameObject.SetActive(true);
|
||
|
||
if (slideCoroutine != null)
|
||
{
|
||
StopCoroutine(slideCoroutine);
|
||
}
|
||
|
||
slideCoroutine = StartCoroutine(AutoSlideRoutine());
|
||
isPlaying = true;
|
||
UpdatePlayPauseButtonText();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 暂停播放
|
||
/// </summary>
|
||
public void Pause()
|
||
{
|
||
if (!isPlaying) return;
|
||
|
||
if (slideCoroutine != null)
|
||
{
|
||
StopCoroutine(slideCoroutine);
|
||
slideCoroutine = null;
|
||
}
|
||
|
||
isPlaying = false;
|
||
transform.parent.gameObject.SetActive(false);
|
||
UpdatePlayPauseButtonText();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动轮播协程
|
||
/// </summary>
|
||
private IEnumerator AutoSlideRoutine()
|
||
{
|
||
while (true)
|
||
{
|
||
yield return new WaitForSeconds(slideInterval);
|
||
if (isPlaying)
|
||
{
|
||
NextImage();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置按钮事件
|
||
/// </summary>
|
||
private void SetupButtons()
|
||
{
|
||
if (prevButton != null)
|
||
{
|
||
prevButton.onClick.RemoveAllListeners();
|
||
prevButton.onClick.AddListener(PreviousImage);
|
||
}
|
||
|
||
if (nextButton != null)
|
||
{
|
||
nextButton.onClick.RemoveAllListeners();
|
||
nextButton.onClick.AddListener(NextImage);
|
||
}
|
||
|
||
if (playPauseButton != null)
|
||
{
|
||
playPauseButton.onClick.RemoveAllListeners();
|
||
playPauseButton.onClick.AddListener(TogglePlayPause);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 切换播放/暂停状态
|
||
/// </summary>
|
||
public void TogglePlayPause()
|
||
{
|
||
if (isPlaying)
|
||
{
|
||
Pause();
|
||
}
|
||
else
|
||
{
|
||
Play();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新播放/暂停按钮文字
|
||
/// </summary>
|
||
private void UpdatePlayPauseButtonText()
|
||
{
|
||
if (playPauseButton != null && playPauseButton.GetComponentInChildren<Text>() != null)
|
||
{
|
||
Text buttonText = playPauseButton.GetComponentInChildren<Text>();
|
||
buttonText.text = isPlaying ? "||" : "▶";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新信息文本
|
||
/// </summary>
|
||
private void UpdateInfoText()
|
||
{
|
||
if (infoText != null)
|
||
{
|
||
if (loadedSprites.Count > 0)
|
||
{
|
||
infoText.text = $"图片 {currentImageIndex + 1}/{loadedSprites.Count}";
|
||
}
|
||
else
|
||
{
|
||
infoText.text = "无图片";
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取完整图片路径
|
||
/// </summary>
|
||
/// <returns>完整路径</returns>
|
||
private string GetFullImagePath()
|
||
{
|
||
return Path.Combine(Application.streamingAssetsPath, imageFolderPath);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前播放状态
|
||
/// </summary>
|
||
/// <returns>是否正在播放</returns>
|
||
public bool IsPlaying()
|
||
{
|
||
return isPlaying;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取图片总数
|
||
/// </summary>
|
||
/// <returns>图片总数</returns>
|
||
public int GetImageCount()
|
||
{
|
||
return loadedSprites.Count;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前图片索引
|
||
/// </summary>
|
||
/// <returns>当前图片索引</returns>
|
||
public int GetCurrentImageIndex()
|
||
{
|
||
return currentImageIndex;
|
||
}
|
||
|
||
void OnDestroy()
|
||
{
|
||
Pause();
|
||
|
||
// 清理加载的纹理
|
||
foreach (Texture2D texture in loadedTextures)
|
||
{
|
||
if (texture != null)
|
||
{
|
||
DestroyImmediate(texture);
|
||
}
|
||
}
|
||
loadedTextures.Clear();
|
||
loadedSprites.Clear();
|
||
}
|
||
} |