unity實現圖片輪播效果_Unity實現圖片輪播組件

游戲中有時候會見到圖片輪播的效果,那么這里就自己封裝了一個,包括自動輪播、切頁按鈕控制、頁碼下標更新、滑動輪播、切頁后的回調等等 。

下面,先上一個簡陋的gif動態效果圖

從圖中可以看出,該示例包括了三張圖片的輪播,左右分別是上一張和下一張的按鈕,右下角顯示了當前是第幾章的頁碼下標。

直接上腳本:

using System;

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.Events;

using UnityEngine.EventSystems;

using UnityEngine.UI;

namespace UnityEngine.UI

{

[AddComponentMenu("UI/Slidershow", 39)] //添加菜單

[ExecuteInEditMode] //編輯模式下可執行

[DisallowMultipleComponent] //不可重復

[RequireComponent(typeof(RectTransform))] //依賴于RectTransform組件

public class Slideshow : UIBehaviour,IPointerDownHandler,IPointerUpHandler

{

public enum MovementType

{

///

/// 循環

///

Circulation, //循環,輪播到最后一頁之后,直接回到第一頁

///

/// 來回往復

///

PingPong, //來回往復,輪播到最后一頁之后,倒序輪播,到第一頁之后,同理

}

public enum MoveDir

{

Left,

Right,

}

[SerializeField]

private MovementType m_movement = MovementType.Circulation;

public MovementType Movement { get { return m_movement; } set { m_movement = value; } }

[SerializeField]

private RectTransform m_content;

public RectTransform Content { get { return m_content; } set { m_content = value; } }

[SerializeField]

private Button m_lastPageButton;

public Button LastPageButton { get { return m_lastPageButton; } set { m_lastPageButton = value; } }

[SerializeField]

private Button m_nextPageButton;

public Button NextPageButton { get { return m_nextPageButton; } set { m_nextPageButton = value; } }

///

/// 自動輪播時長

///

[SerializeField]

private float m_showTime = 2.0f;

public float ShowTime { get { return m_showTime; } set { m_showTime = value; } }

///

/// 是否自動輪播

///

[SerializeField]

private bool m_autoSlide = false;

public bool AutoSlide { get { return m_autoSlide; }set { m_autoSlide = value; } }

///

/// 自動輪播方向,-1表示向左,1表示向右

///

private MoveDir m_autoSlideDir = MoveDir.Right;

///

/// 是否允許拖動切頁

///

[SerializeField]

private bool m_allowDrag = true;

public bool AllowDrag { get { return m_allowDrag; }set { m_allowDrag = value; } }

///

/// 當前顯示頁的頁碼,下標從0開始

///

private int m_curPageIndex = 0;

public int CurPageIndex { get { return m_curPageIndex; } }

///

/// 最大頁碼

///

private int m_maxPageIndex = 0;

public int MaxPageIndex { get { return m_maxPageIndex; } }

///

/// 圓圈頁碼ToggleGroup

///

[SerializeField]

private ToggleGroup m_pageToggleGroup;

public ToggleGroup PageToggleGroup { get { return m_pageToggleGroup; } set { m_pageToggleGroup = value; } }

///

/// 圓圈頁碼Toggle List

///

private List m_pageToggleList;

public List PageToggleLise { get { return m_pageToggleList; }}

//item數目

private int m_itemNum = 0;

public int ItemNum { get { return m_itemNum; } }

//以Toggle為Key,返回頁碼

private Dictionary m_togglePageNumDic = null;

private float m_time = 0f;

private List m_childItemPos = new List();

private GridLayoutGroup m_grid = null;

protected override void Awake()

{

base.Awake();

if (null == m_content)

{

throw new Exception("Slideshow content is null");

}

else

{

m_grid = m_content.GetComponent();

if (m_grid == null)

{

throw new Exception("Slideshow content is miss GridLayoutGroup Component");

}

InitChildItemPos();

}

if (null != m_lastPageButton)

{

m_lastPageButton.onClick.AddListener(OnLastPageButtonClick);

}

if (null != m_nextPageButton)

{

m_nextPageButton.onClick.AddListener(OnNextPageButtonClick);

}

if (null != m_pageToggleGroup)

{

int toggleNum = m_pageToggleGroup.transform.childCount;

if (toggleNum > 0)

{

m_pageToggleList = new List();

m_togglePageNumDic = new Dictionary();

for (int i = 0; i < toggleNum; i++)

{

Toggle childToggle = m_pageToggleGroup.transform.GetChild(i).GetComponent();

if (null != childToggle)

{

m_pageToggleList.Add(childToggle);

m_togglePageNumDic.Add(childToggle, i);

childToggle.onValueChanged.AddListener(OnPageToggleValueChanged);

}

}

m_itemNum = m_pageToggleList.Count;

m_maxPageIndex = m_pageToggleList.Count - 1;

}

}

UpdateCutPageButtonActive(m_curPageIndex);

}

private void InitChildItemPos()

{

int childCount = m_content.transform.childCount;

float cellSizeX = m_grid.cellSize.x;

float spacingX = m_grid.spacing.x;

float posX = -cellSizeX * 0.5f;

m_childItemPos.Add(posX);

for (int i = 1; i < childCount; i++)

{

posX -= cellSizeX + spacingX;

m_childItemPos.Add(posX);

}

}

private void OnPageToggleValueChanged(bool ison)

{

if (ison)

{

Toggle activeToggle = GetActivePageToggle();

if (m_togglePageNumDic.ContainsKey(activeToggle))

{

int page = m_togglePageNumDic[activeToggle];

SwitchToPageNum(page);

}

}

}

private Toggle GetActivePageToggle()

{

if (m_pageToggleGroup == null || m_pageToggleList == null || m_pageToggleList.Count <= 0)

{

return null;

}

for (int i = 0; i < m_pageToggleList.Count; i++)

{

if (m_pageToggleList[i].isOn)

{

return m_pageToggleList[i];

}

}

return null;

}

///

/// 切換至某頁

///

/// 頁碼

private void SwitchToPageNum(int pageNum)

{

if (pageNum < 0 || pageNum > m_maxPageIndex)

{

throw new Exception("page num is error");

}

if (pageNum == m_curPageIndex)

{

//目標頁與當前頁是同一頁

return;

}

m_curPageIndex = pageNum;

if (m_movement == MovementType.PingPong)

{

UpdateCutPageButtonActive(m_curPageIndex);

}

Vector3 pos = m_content.localPosition;

m_content.localPosition = new Vector3(m_childItemPos[m_curPageIndex], pos.y, pos.z);

m_pageToggleList[m_curPageIndex].isOn = true;

if (m_onValueChanged != null)

{

//執行回調

m_onValueChanged.Invoke(m_pageToggleList[m_curPageIndex].gameObject);

}

}

///

/// 根據頁碼更新切頁按鈕active

///

///

private void UpdateCutPageButtonActive(int pageNum)

{

if (pageNum == 0)

{

UpdateLastButtonActive(false);

UpdateNextButtonActive(true);

}

else if (pageNum == m_maxPageIndex)

{

UpdateLastButtonActive(true);

UpdateNextButtonActive(false);

}

else

{

UpdateLastButtonActive(true);

UpdateNextButtonActive(true);

}

}

private void OnNextPageButtonClick()

{

m_time = Time.time; //重新計時

switch (m_movement)

{

case MovementType.Circulation:

SwitchToPageNum((m_curPageIndex + 1) % m_itemNum);

break;

case MovementType.PingPong:

//該模式下,會自動隱藏切頁按鈕

SwitchToPageNum(m_curPageIndex + 1);

break;

default:

break;

}

Debug.Log(m_content.localPosition);

}

private void OnLastPageButtonClick()

{

m_time = Time.time; //重新計時

switch (m_movement)

{

case MovementType.Circulation:

SwitchToPageNum((m_curPageIndex + m_itemNum - 1) % m_itemNum);

break;

case MovementType.PingPong:

//該模式下,會自動隱藏切頁按鈕

SwitchToPageNum(m_curPageIndex - 1);

break;

default:

break;

}

}

private void UpdateLastButtonActive(bool activeSelf)

{

if (null == m_lastPageButton)

{

throw new Exception("Last Page Button is null");

}

bool curActive = m_lastPageButton.gameObject.activeSelf;

if (curActive != activeSelf)

{

m_lastPageButton.gameObject.SetActive(activeSelf);

}

}

private void UpdateNextButtonActive(bool activeSelf)

{

if (null == m_nextPageButton)

{

throw new Exception("Next Page Button is null");

}

bool curActive = m_nextPageButton.gameObject.activeSelf;

if (curActive != activeSelf)

{

m_nextPageButton.gameObject.SetActive(activeSelf);

}

}

private Vector3 m_originDragPos = Vector3.zero;

private Vector3 m_desDragPos = Vector3.zero;

private bool m_isDrag = false;

public void OnPointerDown(PointerEventData eventData)

{

if (!m_allowDrag)

{

return;

}

if (eventData.button != PointerEventData.InputButton.Left)

{

return;

}

if (!IsActive())

{

return;

}

m_isDrag = true;

m_originDragPos = eventData.position;

}

public void OnPointerUp(PointerEventData eventData)

{

m_desDragPos = eventData.position;

MoveDir dir = MoveDir.Right;

if (m_desDragPos.x < m_originDragPos.x)

{

dir = MoveDir.Left;

}

switch (dir)

{

case MoveDir.Left:

if (m_movement == MovementType.Circulation || (m_movement == MovementType.PingPong && m_curPageIndex != 0))

{

OnLastPageButtonClick();

}

break;

case MoveDir.Right:

if (m_movement == MovementType.Circulation || (m_movement == MovementType.PingPong && m_curPageIndex != m_maxPageIndex))

{

OnNextPageButtonClick();

}

break;

}

m_isDrag = false;

}

///

/// 切頁后回調函數

///

[Serializable]

public class SlideshowEvent : UnityEvent { }

[SerializeField]

private SlideshowEvent m_onValueChanged = new SlideshowEvent();

public SlideshowEvent OnValueChanged { get { return m_onValueChanged; } set { m_onValueChanged = value; } }

public override bool IsActive()

{

return base.IsActive() && m_content != null;

}

private void Update()

{

if (m_autoSlide && !m_isDrag)

{

if (Time.time > m_time + m_showTime)

{

m_time = Time.time;

switch (m_movement)

{

case MovementType.Circulation:

m_autoSlideDir = MoveDir.Right;

break;

case MovementType.PingPong:

if (m_curPageIndex == 0)

{

m_autoSlideDir = MoveDir.Right;

}

else if (m_curPageIndex == m_maxPageIndex)

{

m_autoSlideDir = MoveDir.Left;

}

break;

}

switch (m_autoSlideDir)

{

case MoveDir.Left:

OnLastPageButtonClick();

break;

case MoveDir.Right:

OnNextPageButtonClick();

break;

}

}

}

}

}

}

這里提供了一個枚舉MovementType,該枚舉定義了兩種循環方式,其中Circulation循環,是指輪播到最后一頁之后,直接回到第一頁;而PingPong相信大家你熟悉了,就是來回往復的。

其中還提供了對每張圖顯示的時長進行設置,還有是否允許自動輪播的控制,是否允許拖動切頁控制,等等。。其實將圖片作為輪播子元素只是其中之一而已,完全可以將ScrollRect作為輪播子元素,這樣每個子元素又可以滑動閱覽了。

這里還提供了兩個編輯器腳本,一個是SlideshowEditor(依賴Slideshow組件),另一個是給用戶提供菜單用的CreateSlideshow,代碼分別如下:

using System.Collections;

using System.Collections.Generic;

using UnityEditor;

using UnityEngine;

using UnityEngine.EventSystems;

using UnityEngine.UI;

public class CreateSlideshow : Editor

{

private static GameObject m_slideshowPrefab = null;

private static GameObject m_canvas = null;

[MenuItem("GameObject/UI/Slideshow")]

static void CreateSlideshowUI(MenuCommand menuCommand)

{

if (null == m_slideshowPrefab)

{

m_slideshowPrefab = Resources.Load("Slideshow");

if (null == m_slideshowPrefab)

{

Debug.LogError("Prefab Slideshow is null");

return;

}

}

m_canvas = menuCommand.context as GameObject;

if (m_canvas == null || m_canvas.GetComponentInParent() == null)

{

m_canvas = GetOrCreateCanvasGameObject();

}

GameObject go = GameObject.Instantiate(m_slideshowPrefab, m_canvas.transform);

go.transform.localPosition = Vector3.zero;

go.name = "Slideshow";

Selection.activeGameObject = go;

}

static public GameObject GetOrCreateCanvasGameObject()

{

GameObject selectedGo = Selection.activeGameObject;

Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent() : null;

if (canvas != null && canvas.gameObject.activeInHierarchy)

return canvas.gameObject;

canvas = Object.FindObjectOfType(typeof(Canvas)) as Canvas;

if (canvas != null && canvas.gameObject.activeInHierarchy)

return canvas.gameObject;

return CreateCanvas();

}

public static GameObject CreateCanvas()

{

var root = new GameObject("Canvas");

root.layer = LayerMask.NameToLayer("UI");

Canvas canvas = root.AddComponent();

canvas.renderMode = RenderMode.ScreenSpaceOverlay;

root.AddComponent();

root.AddComponent();

Undo.RegisterCreatedObjectUndo(root, "Create " + root.name);

CreateEventSystem();

return root;

}

public static void CreateEventSystem()

{

var esys = Object.FindObjectOfType();

if (esys == null)

{

var eventSystem = new GameObject("EventSystem");

GameObjectUtility.SetParentAndAlign(eventSystem, null);

esys = eventSystem.AddComponent();

eventSystem.AddComponent();

Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name);

}

}

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEditor.Advertisements;

using UnityEngine.UI;

namespace UnityEditor.UI

{

[CustomEditor(typeof(Slideshow), true)]

public class SlideshowEditor : Editor

{

SerializedProperty m_movement;

SerializedProperty m_content;

SerializedProperty m_lastPageButton;

SerializedProperty m_nextPageButton;

SerializedProperty m_showTime;

SerializedProperty m_pageToggleGroup;

SerializedProperty m_onValueChanged;

SerializedProperty m_allowDrag;

SerializedProperty m_autoSlide;

protected virtual void OnEnable()

{

m_movement = serializedObject.FindProperty("m_movement");

m_content = serializedObject.FindProperty("m_content");

m_lastPageButton = serializedObject.FindProperty("m_lastPageButton");

m_nextPageButton = serializedObject.FindProperty("m_nextPageButton");

m_showTime = serializedObject.FindProperty("m_showTime");

m_pageToggleGroup = serializedObject.FindProperty("m_pageToggleGroup");

m_onValueChanged = serializedObject.FindProperty("m_onValueChanged");

m_allowDrag = serializedObject.FindProperty("m_allowDrag");

m_autoSlide = serializedObject.FindProperty("m_autoSlide");

}

public override void OnInspectorGUI()

{

serializedObject.Update();

EditorGUILayout.PropertyField(m_movement);

EditorGUILayout.PropertyField(m_content);

EditorGUILayout.PropertyField(m_lastPageButton);

EditorGUILayout.PropertyField(m_nextPageButton);

EditorGUILayout.PropertyField(m_allowDrag);

EditorGUILayout.PropertyField(m_autoSlide);

EditorGUILayout.PropertyField(m_showTime);

EditorGUILayout.PropertyField(m_pageToggleGroup);

EditorGUILayout.Space();

EditorGUILayout.PropertyField(m_onValueChanged);

//不加這句代碼,在編輯模式下,無法將物體拖拽賦值

serializedObject.ApplyModifiedProperties();

}

}

}

這兩個腳本中使用了一些拓展編輯器的知識,后續在另外寫博客介紹 。

其中腳本CreateSlideshow中使用UGUI源碼中的DefaultControls腳本里的方法,有興趣可以去下載查閱。

Demo工程下載地址

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/259914.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/259914.shtml
英文地址,請注明出處:http://en.pswp.cn/news/259914.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[置頂] 2013騰訊編程馬拉松初賽第4場(3月24)(HDU 4520 HDU4521 HDU4522 HDU4523 HDU4524)...

話說昨天比賽終于拿到一個不錯的名次&#xff0c;rank77&#xff0c;對于我們這種ACM弱菜的學校來說已經很好了&#xff0c;可惜我1003用了倆floyd超時&#xff0c;如果我最近稍微搞搞圖論的話&#xff0c;用個bellman&#xff0c;或者SPFA&#xff0c;絕對超不了了就。。。哎。…

計算機學院年會,重慶大學計算機學院舉行2019年迎新晚會

2019年12月6號晚&#xff0c;重慶大學計算機學院2019年迎新晚會在蘭園小劇場舉行。出席本次晚會的嘉賓有計算機學院黨委副書記兼紀委書記郭坤銀、黨委組織員劉霜、2016級輔導員李若菡老師、2017級輔導員古曦老師、2018級輔導員鄭田青老師、2019級輔導員謝璧如老師。本次晚會的主…

[轉貼]Cocos2d-x3.2與OpenGL渲染總結(一)Cocos2d-x3.2的渲染流程

看了opengles有一段時間了&#xff0c;算是了解了一下下。然后&#xff0c;就在基本要決定還是回歸cocos2dx 3.2的&#xff0c;看了這篇好文章&#xff0c;欣喜轉之~ 推薦看原帖&#xff1a; Cocos2d-x3.2與OpenGL渲染總結(一)Cocos2d-x3.2的渲染流程 最近幾天&#xff0c;我都…

省賽熱身賽之Median

原題&#xff1a; Description A median is described as the numeric value separating the higher half of a list, from the lower half. The median of a finite list of numbers can be found by arranging all the elements from lowest value to highest value and pick…

win32 段寄存器怎么尋址

32位cpu 地址線擴展成了32位&#xff0c;這和數據線的寬度是一致的。因此&#xff0c;在32位機里其實并不需要采用“物理地址段&#xff1a;偏移”這種地址表達方式。原來在16位機里規定的 每一個段不大于64kb在32位機里也不是必要的。所以&#xff0c;對于32位機來講&#xff…

聯想拯救者y7000p加內存條_筆記本怎么升級內存和硬盤 聯想Y7000P加裝內存和硬盤圖文教程 (全文)...

一般目前新買的筆記本電腦,大都是標配8GB內存和單塊固態硬盤,內存和硬盤容量適中,但對于一些制圖設計、偏大型游戲,又或者對硬盤存儲要求比較高的用戶來說,顯然就不太夠用,這時候我們一般會通過升級內存和硬盤來解決。那么,筆記本怎么升級內存和硬盤?下面以聯想Y7000P筆…

計算機組裝與維護實訓1,計算機組裝與維護實訓報告[1]

計算機組裝與維護實訓報告[1] (12頁)本資源提供全文預覽&#xff0c;點擊全文預覽即可全文預覽,如果喜歡文檔就下載吧&#xff0c;查找使用更方便哦&#xff01;11.90 積分實習報告設計題目&#xff1a; 計算機組裝與維護實習 專業班級&#xff1a; 計算機應用103班 學生姓名&a…

node.js-------使用路由模塊

路由需要的信息&#xff0c;包括URL 及GET 或 POST參數。路由根據這些參數執行相應的js處理程序&#xff0c;因此&#xff0c;需要在HTTP請求中提取出URL以及GET或POST參數。這些請求參數在request對象中&#xff0c;這個對象是onRequest()回調函數的第一個參數。需要提取這些信…

Docker - 在CentOS 7中安裝Docker

在CentOS 7中安裝Docker 1-確認系統信息 # cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) # uname -a Linux CentOS-7 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux 2-安裝docker # yum -y install docker 3…

HDU 1715 大菲波數 (大數問題)

/* 復習大數問題&#xff1b; */ #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <iomanip> using namespace std;int nu…

springcloud 相同服務名_SpringCloud系列之SpringCloud Stream

SpringCloud Stream技術興起的原因&#xff1a;為了解決系統中不同中間件的適配問題&#xff0c;出現了cloud stream&#xff0c;采用適配綁定的方式&#xff0c;自動給不同的MQ之間進行切換。屏蔽底層消息中間件的差異&#xff0c;降低切換成本&#xff0c;統一消息的編程模型…

計算機意外重啟或遇錯誤無法繼續,計算機意外地重新啟動或遇到錯誤如何解決?...

電腦小白在重裝系統后難免會遇到些問題&#xff0c;有的容易處理&#xff0c;有的會有些棘手。那么&#xff0c;計算機意外地重新啟動或遇到錯誤如何解決?今天快啟動小編為大家分享詳細的計算機意外地重新啟動或遇到錯誤的解決方法&#xff0c;獻給對系統重裝知識不太了解的小…

jqueryui的Tooltip使用方法

http://api.jqueryui.com/tooltip/#option-position&#xff0c;詳細使用方法。 http://jqueryui.com/tooltip/&#xff0c;DEMO。 content使用 $( ".selector" ).tooltip({ content: "Awesome title!" });//div及相關標簽使用樣式&#xff0c;鼠標放上去時…

iOS 開發者賬號共用發布證書 (Distribution)問題

蘋果客服回復&#xff1a; 1.第一臺申請發布證書的電腦&#xff0c;從鑰匙串中導出發布證書(Distribution)頒發的request文件&#xff1f;然后在第二臺電腦上用request文件新生成一個Distribution證書&#xff0c;這個是可以共用的&#xff1f;&#xff08;不理解還是理解錯了&…

JMeter web 測試

2019獨角獸企業重金招聘Python工程師標準>>> JMeter web 測試 http://jmeter.apache.org/usermanual/build-web-test-plan.html 轉載于:https://my.oschina.net/276172622/blog/808957

scala 連接oracle_一分鐘教你學會用java連接Oracle數據庫

package java_jdbc;//java連接Oracle數據庫import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.Statement;public class JdbcOracleTest {public static void main(String[] args) {// TODO Auto-generated method stub//1.…

計算機軟件記不住設置,想知道電腦密碼記不住了怎么辦

635509517回答數&#xff1a;23216 | 被采納數&#xff1a;32017-01-09 17:51:10方法一&#xff1a;(1)啟動電腦&#xff0c;使用DOS啟動盤(比如&#xff1a;Windows 98啟動盤)進入純DOS狀態。(2)在DOS提示符下&#xff0c;根據下面步驟操作&#xff1a;cd\\ (切換到根目錄)c…

vue-cli#2.0 webpack 配置分析

目錄結構&#xff1a; ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-server.js │ ├── utils.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js…

initWithNibName與viewDidLoad的執行關系以及順序

一個ViewController&#xff0c;一般通過init或initWithNibName來加載。二者沒有什么不同&#xff0c;init最終還是要調用initWithNibName方法&#xff08;除非這個ViewController沒有nib文件&#xff09;。 我們經常在initWithNibName方法中初始化視圖&#xff0c;變量或者其他…

120xa正反轉參數_你知道變頻器的“正反轉死區時間”嗎?它的“停機方式”有幾種?...

若你我之間有緣&#xff0c;關注作者又何妨&#xff1f;兩情若是久長時&#xff0c;又豈在朝朝暮暮。大家好&#xff01;我是江郎&#xff0c;一個踏踏實實的維修工。本期我們仍然探討兩個問題&#xff0c;如標題所述&#xff0c;#變頻器#“死區時間”和“停機方式”&#xff0…