热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

UnityNGUIScrollView苹果式滑动

又回来写博客了,这回已经开始上班了,所以就发一发工作中解决的难题吧。单个展示Panel(苹果式)以前对UI的滑动组件很烦心,不是很会用,这回项目要求写一个类似于苹果的文件滑动效果,





又回来写博客了,这回已经开始上班了,所以就发一发工作中解决的难题吧。


单个展示Panel(苹果式)


以前对UI的滑动组件很烦心,不是很会用,这回项目要求写一个类似于苹果的文件滑动效果,但是苹果就展示一个文件,而我这边展示数目不定,头疼!


下面就直接来干货吧~,这里附送一个苹果式滑动解决方式 : 点这里


多个展示Panel(改写)


而我追求的效果呢,稍微改动一下,如下:(中间显示很多个,旁边的在叠起来的效果)


Unity NGUI ScrollView 苹果式滑动


这里我们采用比例的方式,这样好控制一些。


几个比较重要的点:



  • 每个Panel之间的比例差值



_offset = 1f / (totalPanelCount - showPanelCount); // 1f / (总共Panel - 展示Panel)



  • 获得拖动结束要偏移到的目标位置



private float GetTarget()
{
return Mathf.Clamp01(Mathf.RoundToInt(_scrollValue / _offset) * _offset); // 取得最近的整数位
}



  • 分成三个区域,左缩放区域,右缩放区域,中间展示区域



 1     private void AnimationCore(int index)
2 {
3 float sourcePos = index * _offset;
4 // 左边区域
5 if (sourcePos < _scrollValue)
6 {
7 float dif = _scrollValue - sourcePos;
8 int depth = _currentIndex - index;
9 _panelPool[index].transform.SetSiblingIndex(totalPanelCount - depth - 2);
10 _panelPool[index].transform.localPosition = Vector3.Lerp(_panelPool[index].transform.localPosition, GetTargetPos(index, dif, true), 100 * Time.deltaTime);
11 }
12 // 右边区域
13 else if (sourcePos > _scrollValue + _offset * (showPanelCount - 1))
14 {
15 float dif = sourcePos - _scrollValue - _offset * (showPanelCount - 1);
16 int depth = index - _currentIndex - showPanelCount + 1;
17 _panelPool[index].transform.SetSiblingIndex(totalPanelCount - depth - 2);
18 _panelPool[index].transform.localPosition = Vector3.Lerp(_panelPool[index].transform.localPosition, GetTargetPos(index, dif, false), 100 * Time.deltaTime);
19 }
20 // 中间区域
21 else
22 {
23 _panelPool[index].transform.SetAsLastSibling();
24 _panelPool[index].transform.localPosition = Vector3.Lerp(_panelPool[index].transform.localPosition, _panelPoolPos[index], 100 * Time.deltaTime);
25 }
26 }



  • 获取Panel的滑动偏移位置



    private Vector3 GetTargetPos(int index, float dif, bool isLeft)
{
float offSetDif = 60 / _offset * dif;
if (isLeft)
{
return _panelPoolPos[index] + Vector3.right * offSetDif; // 左区域
}
else
{
return _panelPoolPos[index] - Vector3.right * offSetDif; // 右区域
}
}



  • 获取当前滑动的位置



 1     private float _scrollValue
2 {
3 get
4 {
5 return _scrollRect.horizontal ?
6 _scrollRect.horizontalNormalizedPosition :
7 _scrollRect.verticalNormalizedPosition;
8 }
9
10 set
11 {
12 if (_scrollRect.horizontal)
13 {
14 _scrollRect.horizOntalNormalizedPosition= value;
15 }
16 else
17 {
18 _scrollRect.verticalNormalizedPosition = value;
19 }
20 }
21 }


需要继承NGUI的EventSystem的时间来触发管理拖动 PS:用DOTween做最后的回滑效果


完整代码如下:



  1 using System;
2 using UnityEngine;
3 using UnityEngine.EventSystems;
4 using UnityEngine.UI;
5 using DG.Tweening;
6
7 [RequireComponent(typeof(ScrollRect))]
8 public class ScrollController : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
9 {
10 [Tooltip("创建出来的对象")]
11 public GameObject imageObject;
12 [Tooltip("展示页面数量")]
13 public int showPanelCount = 8;
14 [Tooltip("总计页面数量")]
15 public int totalPanelCount = 20;
16 [Tooltip("拖动结束制动弹回制动时间")]
17 public float endDragMoveTime = 1f;
18 public Ease doTweenEase = Ease.OutExpo;
19
20 private int _currentIndex;
21 private ScrollRect _scrollRect;
22 private Tweener _tweener;
23 private GameObject[] _panelPool = new GameObject[20];
24 private Vector3[] _panelPoolPos = new Vector3[20];
25 private float _offset;
26
27 void Start()
28 {
29 _currentIndex = 1;
30 _scrollRect = GetComponent();
31 _scrollRect.inertia = false;
32
33 for (int i = 0; i )
34 {
35 GameObject go = Instantiate(imageObject) as GameObject;
36 go.transform.SetParent(_scrollRect.content.transform);
37 go.GetComponent().sizeDelta = new Vector2(100, 200);
38 go.GetComponent().anchorMax = new Vector2(0, 0.5f);
39 go.GetComponent().anchorMin = new Vector2(0, 0.5f);
40 go.GetComponent().pivot = new Vector2(0, 0.5f);
41 go.GetComponent().anchoredPosition = new Vector2(100 + 100 * i, 0);
42 go.transform.localScale = Vector3.one;
43 _panelPool[i] = go;
44 _panelPoolPos[i] = go.transform.localPosition;
45 }
46
47 _scrollRect.content.GetComponent().sizeDelta = new Vector2(totalPanelCount * 100 + 200, 200);
48
49 _offset = 1f / (totalPanelCount - showPanelCount);
50
51 for (int i = 0; i )
52 {
53 AnimationCore(i);
54 }
55 }
56
57 public void OnBeginDrag(PointerEventData eventData)
58 {
59 if (_tweener != null && _tweener.IsActive())
60 {
61 _tweener.Kill();
62 }
63 }
64
65 public void OnDrag(PointerEventData eventData)
66 {
67 _currentIndex = Mathf.RoundToInt(GetTarget() * (totalPanelCount - showPanelCount));
68
69 OnDragAnimation();
70 }
71
72 public void OnEndDrag(PointerEventData eventData)
73 {
74 _tweener = DOTween.To(() => _scrollValue, (v) => _scrollValue = v, GetTarget(), endDragMoveTime).SetEase(doTweenEase);
75 _tweener.OnUpdate= () =>
76 {
77 OnDragAnimation();
78 };
79 }
80
81 private void OnDragAnimation()
82 {
83 //向左拉动(解决层级问题)
84 if (_scrollValue > 0)
85 {
86 for (int i = 0; i )
87 {
88 AnimationCore(i);
89 }
90 }
91 else
92 {
93 for (int i = totalPanelCount - 1; i >= 0; i--)
94 {
95 AnimationCore(i);
96 }
97 }
98 }
99
100 private void AnimationCore(int index)
101 {
102 float sourcePos = index * _offset;
103 // 左边区域
104 if (sourcePos < _scrollValue)
105 {
106 float dif = _scrollValue - sourcePos;
107 int depth = _currentIndex - index;
108 _panelPool[index].transform.SetSiblingIndex(totalPanelCount - depth - 2);
109 _panelPool[index].transform.localPosition = Vector3.Lerp(_panelPool[index].transform.localPosition, GetTargetPos(index, dif, true), 100 * Time.deltaTime);
110 }
111 // 右边区域
112 else if (sourcePos > _scrollValue + _offset * (showPanelCount - 1))
113 {
114 float dif = sourcePos - _scrollValue - _offset * (showPanelCount - 1);
115 int depth = index - _currentIndex - showPanelCount + 1;
116 _panelPool[index].transform.SetSiblingIndex(totalPanelCount - depth - 2);
117 _panelPool[index].transform.localPosition = Vector3.Lerp(_panelPool[index].transform.localPosition, GetTargetPos(index, dif, false), 100 * Time.deltaTime);
118 }
119 // 中间区域
120 else
121 {
122 _panelPool[index].transform.SetAsLastSibling();
123 _panelPool[index].transform.localPosition = Vector3.Lerp(_panelPool[index].transform.localPosition, _panelPoolPos[index], 100 * Time.deltaTime);
124 }
125 }
126
127 ///
128 /// 获取到页面的偏移后位置
129 ///

130 ///
131 private Vector3 GetTargetPos(int index, float dif, bool isLeft)
132 {
133 float offSetDif = 60 / _offset * dif;
134 if (isLeft)
135 {
136 return _panelPoolPos[index] + Vector3.right * offSetDif;
137 }
138 else
139 {
140 return _panelPoolPos[index] - Vector3.right * offSetDif;
141 }
142 }
143
144 ///
145 /// 获得偏转目标位置
146 ///

147 ///
148 private float GetTarget()
149 {
150 return Mathf.Clamp01(Mathf.RoundToInt(_scrollValue / _offset) * _offset);
151 }
152
153 ///
154 /// 当前滑动位置
155 ///

156 ///
157 private float _scrollValue
158 {
159 get
160 {
161 return _scrollRect.horizontal ?
162 _scrollRect.horizontalNormalizedPosition :
163 _scrollRect.verticalNormalizedPosition;
164 }
165
166 set
167 {
168 if (_scrollRect.horizontal)
169 {
170 _scrollRect.horizOntalNormalizedPosition= value;
171 }
172 else
173 {
174 _scrollRect.verticalNormalizedPosition = value;
175 }
176 }
177 }
178 }


 







推荐阅读
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 尽管使用TensorFlow和PyTorch等成熟框架可以显著降低实现递归神经网络(RNN)的门槛,但对于初学者来说,理解其底层原理至关重要。本文将引导您使用NumPy从头构建一个用于自然语言处理(NLP)的RNN模型。 ... [详细]
  • 本文详细介绍了 GWT 中 PopupPanel 类的 onKeyDownPreview 方法,提供了多个代码示例及应用场景,帮助开发者更好地理解和使用该方法。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • 本文基于刘洪波老师的《英文词根词缀精讲》,深入探讨了多个重要词根词缀的起源及其相关词汇,帮助读者更好地理解和记忆英语单词。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 本文详细介绍了如何使用 Yii2 的 GridView 组件在列表页面实现数据的直接编辑功能。通过具体的代码示例和步骤,帮助开发者快速掌握这一实用技巧。 ... [详细]
  • ServiceStack与Swagger的无缝集成指南
    本文详细介绍了如何在ServiceStack项目中集成Swagger,以实现API文档的自动生成和在线测试。通过本指南,您将了解从配置到部署的完整流程,并掌握如何优化API接口的开发和维护。 ... [详细]
author-avatar
水门街口卖瓜子的
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有