热门标签 | 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 }


 







推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文将介绍如何编写一些有趣的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. ... [详细]
  • IneedtofocusTextCellsonebyoneviaabuttonclick.ItriedlistView.ScrollTo.我需要通过点击按钮逐个关注Tex ... [详细]
  • 本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • c# – UWP:BrightnessOverride StartOverride逻辑 ... [详细]
  • 本文详细介绍了如何使用 Yii2 的 GridView 组件在列表页面实现数据的直接编辑功能。通过具体的代码示例和步骤,帮助开发者快速掌握这一实用技巧。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • ASP.NET MVC中Area机制的实现与优化
    本文探讨了在ASP.NET MVC框架中,如何通过Area机制有效地组织和管理大规模应用程序的不同功能模块。通过合理的文件夹结构和命名规则,开发人员可以更高效地管理和扩展项目。 ... [详细]
  • 本文深入探讨了C++对象模型中的一些细节问题,特别是虚拟继承和析构函数的处理。通过具体代码示例和详细分析,揭示了书中某些观点的不足之处,并提供了更合理的解释。 ... [详细]
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社区 版权所有