设计好用的触控操作手势
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计好用的触控操作手势相关的知识,希望对你有一定的参考价值。
参考技术A 随着移动设备的快速发展,触控手势操作逐渐成为人们日常生活中最为常用的与产品之间的交互操作方式。与鼠标和键盘的交互方式不同,触控手势交互更加符合人们的自然行为习惯,也因此可以得到快速的发展。本文框架内容来自腾讯交互设计师陈晓畅“如何设计好用的触控手势”。首先,要想设计好用、易用的触控操作手势,那么我们就要先来了解一个名词,即”NUI“。NUI是指”自然交互界面“,与传统的图形交互界面GUI不同。NUI更注重多维度的与用户产生互动,包括视觉、听觉、触觉等等,最大程度的模仿人们在现实生活中的操作行为习惯,遵循用户行为规律。因此,要想设计好好用的手势,那么我们就要在日常多研究用户的操作行为。那么如何挖掘用户的操作行为呢,在这里我要引入一个概念,即”场景“。
交互设计中,有一个最重要的设计方法,是基于场景设计。这里的场景,是指人们在日常生活中遇到的问题,想要达到的目的等等。可以这样理解,因为在这个场景中我有这样的需求,所以我的产品才设计成这样。对于交互设计来说,如何评判交互的好坏,很重要的一点,也是看能否满足场景化需求。而对于移动端设备来说,它所面对的用户使用场景是多元化的。在路上、在候车大厅、在吃饭的时候、在购物的时候...所处的自然环境是多元且多变的。这也就要求我们在设计移动端触控操作手势的时候,要考虑足够全面的场景。
那么我们在设计移动端触控手势的时候,可能会遇到哪些问题,要求我们必须考虑呢?
1.用户在使用移动端设备的时候,注意力容易被分散。
2.用户在使用移动端设备的时候,使用时间大多碎片化,多频不长。
3.用户在使用移动端设备的时候,任务容易被打断,被打断的原因可能来自手机内部信息的干扰,也有可能来自外界物理的干扰。
4.用户在使用移动端设备的时候,可能会单手操作。
以上这些情况,都是我们在设计交互手势的时候,要考虑的特殊场景。在这些特殊场景下,用户也要能够轻松顺利地完成任务,才是我们要达到的目的。
好用的交互手势是简单的方便的。 手势一定要足够简单,能够让用户轻松掌握其规律,能够满足用户单手操作的需求。
好用的交互手势是容易记忆的。 在设计交互手势的时候一定不要设计过于复杂的手势,因为手势越复杂,用户的操作记忆成本越高,越容易忘记操作方式导致中断任务。
好用的交互手势是符合人们的认知习惯的。 好用的交互手势一定是遵循人们的自然习惯和意识,更多的采用”下意识设计“会让你的交互手势更容易被人们记住和使用。
好用的交互手势是会给予用户及时反馈的 ,不仅仅是视觉上的反馈,包括触觉上震动的反馈,听觉上声音的反馈都是很重要。在尼尔森关于交互设计十原则中,最重要的一点就是要提供用户及时反馈。在交互手势设计中也是如此,及时的反馈会给用户一种”一切都在我的掌握之下的感觉“。
好用的交互手势是实用的。 不要去设计一些没必要的交互手势,让用户用最小的操作成本去完成任务。
其实这里讲的交互手势设计的原则和前文所叙述的好用的交互手势是怎样的有异曲同工之妙,好用的交互手势一定是满足这些设计原则的。下面我来简单讲述,交互手势设计的一些原则:
1.符合用户认知行为习惯 。手势设计要最大程度的还原现实生活中人们的行为习惯,符合用户认知。
2.减少用户记忆成本 。不要设计复杂的手势,增加用户的记忆成本,用最简单易用的手势。
3.考虑用户的应用场景 。在某个场景下,用户是单手操作还是双手操作,单手操作的情况下,将操作热区安排在用户可控的范围内。
4.及时反馈。 包括视觉、听觉和触觉上的反馈。
5.操作可逆。 提供用户取消操作的途径,比如微信语音说话,上划手势取消发送。
6.保证产品手势的一致性。 在产品中要保证交互手势的一致性,不要相同的功能下采用多种交互手势。
交互手势是我们现在最常用的一种交互形式,我们每天都在移动端设备上进行大量的操作。好用的交互手势,会提升用户使用产品的愉悦感和满足感,相反不好的交互手势则会阻碍用户完成任务需求,产生挫败感。手势设计关乎产品的用户体验。作为交互设计师,我们要掌握交互手势设计相关的设计原则,为用户设计好用且易用的手势操作。
最后要感谢陈晓畅设计师,如果没有他的总结,我也不会学习到关于手势设计相关的知识,在这里把他文章中的精华总结并加上我个人的理解,写成了这篇分享,希望对各位有所帮助。也希望各位设计师朋友可以广提见解,一起交流。
Unity 之 移动设备的触控操作
http://blog.csdn.net/anyuanlzh/article/details/18367941
这篇博文将简单的记录,如何用unity处理在移动设备上的触控操作。
iOS和Android设备能够支持多点触控。在unity中你可以通过Input.touches属性集合访问在最近一帧中触摸在屏幕上的每一根手指的状态数据。简单的触控响应实现起很简单,不过一些复杂的触控响应或触控手势什么的,还是使用一些第三方的插件吧,当然你也可以自己封装。不管什么情况,了解决unity原生api还是非常必要的。
相关的api
1、Toch类:用来记录一个手指触摸在屏幕上的状态与位置的各种相关数据。这其它中只有两个属性是你要注意的,就是Touch.fingerId和Touch.tapCount。
Touch.fingerId: 一个Touch的标识。Input.touches数组中的同一个索引在两帧之前,指向的可不一定是同一个Touch。用来标识某个具体的touch一定要用fingerId,在分析手势时、或处理多点触控时,fingerId是非常重要的。
Touch.tapCount: 点击的总人数,这个属性可以用来模拟“双击”的效果。
这里先普及一个概念吧,一个touch的生命周期是:当一个手指接触到触屏时,产生一个Touch,并分配它一个fingerId,到这个手指离开触屏这个touch就有了。在它整个生命周期里,它的figerId是不会变的。死掉的touch所使用过fingerId当也会被之后的touch多次使用。ps:其实也不是手指一离开,这个touch就立马死掉。还有一种特殊的情况就是:在手指敲开的地方,在一个很短的时间内,一个手指又回到这个地方的话,这个touch没不会死掉,这个也是Touch.tapCount属于的由来吧。这个touch生命周期,是我自己理解的,实际情况是不是这样就不知道了,料想也不会差的太多。
2、TouchPhase枚举:它列表描述了手指触摸的几种状态。对应Touch类中的phase属性。这是状态分别是:Began、Move、Stationary、Ended、Canceled。
3、Input.touches:一个Touch数组,代表着当前帧,所有手指在屏幕上的触碰状态与相关数据。(只读)
4、Input.touchCount: 触摸数量,相当于Input.touches.Length。(只读)
5、Input.multiTouchEnabled:设置与指示当前系统(注意不是指设备哦!)是否启用多点触控。不过这个属性有点怪,我在电脑上测试给它赋false不会报错但完全是没有用的,它的值一值是true. 不过在我的安卓手机上测试是正常的!Ture表示支持多点触控(一般是5点);False表示单点触控。
6、Input.GetTouch(int index):安索引值获取一个Touch对象。
下面一个测试Demo
1、简述:
这个Demo主要是让你的触摸可视化的显示在你的手机(或平板)屏幕上;
并实时记录和显示了手指在屏幕上的状态和相关数据。
2、相关截图:
3、脚本就一个
- /*
- * author: AnYuanLzh
- * date: 2014/01/18
- * */
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- public class MyTouch : MonoBehaviour
- {
- /// <summary>
- /// 定义的一个手指类
- /// </summary>
- class MyFinger
- {
- public int id = -1;
- public Touch touch;
- static private List<MyFinger> fingers = new List<MyFinger>();
- /// <summary>
- /// 手指容器
- /// </summary>
- static public List<MyFinger> Fingers
- {
- get
- {
- if(fingers.Count==0)
- {
- for(int i=0; i<5; i++)
- {
- MyFinger mf = new MyFinger();
- mf.id = -1;
- fingers.Add(mf);
- }
- }
- return fingers;
- }
- }
- }
- // 小圈圈:用来实时显示手指触摸的位置
- GameObject[] marks = new GameObject[5];
- public GameObject markPerfab = null;
- // 粒子效果:来所显示手指手动的大概路径
- ParticleSystem[] particles = new ParticleSystem[5];
- public ParticleSystem particlePerfab = null;
- // Use this for initialization
- void Start ()
- {
- // init marks and particles
- for(int i=0; i<MyFinger.Fingers.Count; i++)
- {
- GameObject mark = Instantiate(markPerfab, Vector3.zero, Quaternion.identity) as GameObject;
- mark.transform.parent = this.transform;
- mark.SetActive(false);
- marks[i] = mark;
- ParticleSystem particle = Instantiate(particlePerfab, Vector3.zero, Quaternion.identity) as ParticleSystem;
- particle.transform.parent = this.transform;
- particle.Pause();
- particles[i] = particle;
- }
- }
- // Update is called once per frame
- void Update ()
- {
- Touch[] touches = Input.touches;
- // 遍历所有的已经记录的手指
- // --掦除已经不存在的手指
- foreach(MyFinger mf in MyFinger.Fingers)
- {
- if(mf.id == -1)
- {
- continue;
- }
- bool stillExit = false;
- foreach(Touch t in touches)
- {
- if(mf.id == t.fingerId)
- {
- stillExit = true;
- break;
- }
- }
- // 掦除
- if(stillExit == false)
- {
- mf.id = -1;
- }
- }
- // 遍历当前的touches
- // --并检查它们在是否已经记录在AllFinger中
- // --是的话更新对应手指的状态,不是的放放加进去
- foreach(Touch t in touches)
- {
- bool stillExit = false;
- // 存在--更新对应的手指
- foreach(MyFinger mf in MyFinger.Fingers)
- {
- if(t.fingerId == mf.id)
- {
- stillExit = true;
- mf.touch = t;
- break;
- }
- }
- // 不存在--添加新记录
- if(!stillExit)
- {
- foreach(MyFinger mf in MyFinger.Fingers)
- {
- if(mf.id == -1)
- {
- mf.id = t.fingerId;
- mf.touch = t;
- break;
- }
- }
- }
- }
- // 记录完手指信息后,就是响应相应和状态记录了
- for(int i=0; i< MyFinger.Fingers.Count; i++)
- {
- MyFinger mf = MyFinger.Fingers[i];
- if(mf.id != -1)
- {
- if(mf.touch.phase == TouchPhase.Began)
- {
- marks[i].SetActive(true);
- marks[i].transform.position = GetWorldPos(mf.touch.position);
- particles[i].transform.position = GetWorldPos(mf.touch.position);
- }
- else if(mf.touch.phase == TouchPhase.Moved)
- {
- marks[i].transform.position = GetWorldPos(mf.touch.position);
- if(!particles[i].isPlaying)
- {
- particles[i].loop = true;
- particles[i].Play();
- }
- particles[i].transform.position = GetWorldPos(mf.touch.position);
- }
- else if(mf.touch.phase == TouchPhase.Ended)
- {
- marks[i].SetActive(false);
- marks[i].transform.position = GetWorldPos(mf.touch.position);
- particles[i].loop = false;
- particles[i].Play();
- particles[i].transform.position = GetWorldPos(mf.touch.position);
- }
- else if(mf.touch.phase == TouchPhase.Stationary)
- {
- if(particles[i].isPlaying)
- {
- particles[i].Pause();
- }
- particles[i].transform.position = GetWorldPos(mf.touch.position);
- }
- }
- else
- {
- ;
- }
- }
- // exit
- if(Input.GetKeyDown(KeyCode.Home) || Input.GetKeyDown(KeyCode.Escape))
- {
- Application.Quit();
- }
- // // test
- // if(Input.GetMouseButtonDown(0))
- // {
- // GameObject mark = Instantiate(markPerfab, Vector3.zero, Quaternion.identity) as GameObject;
- // mark.transform.parent = this.transform;
- // mark.transform.position = GetWorldPos(Input.mousePosition);
- //
- // ParticleSystem particle = Instantiate(particlePerfab, Vector3.zero, Quaternion.identity) as ParticleSystem;
- // particle.transform.parent = this.transform;
- // particle.transform.position = GetWorldPos(Input.mousePosition);
- // particle.loop = false;
- // particle.Play();
- // }
- }
- /// <summary>
- /// 显示相关高度数据
- /// </summary>
- void OnGUI()
- {
- GUILayout.Label("支持的手指的数量:" + MyFinger.Fingers.Count);
- GUILayout.BeginHorizontal(GUILayout.Width(Screen.width));
- for(int i=0; i< MyFinger.Fingers.Count; i++)
- {
- GUILayout.BeginVertical();
- MyFinger mf = MyFinger.Fingers[i];
- GUILayout.Label("手指" + i.ToString());
- if(mf.id != -1)
- {
- GUILayout.Label("Id: " + mf.id);
- GUILayout.Label("状态: " + mf.touch.phase.ToString());
- }
- else
- {
- GUILayout.Label("没有发现!");
- }
- GUILayout.EndVertical();
- }
- GUILayout.EndHorizontal();
- }
- public Vector3 GetWorldPos(Vector2 screenPos)
- {
- return Camera.main.ScreenToWorldPoint(new Vector3(screenPos.x, screenPos.y, Camera.main.nearClipPlane + 10));
- }
- }
4、相关下载(点下面的链接)
项目文件 和 发布好的apk,下载点这里(不需要下载积分)。
注:这个apk对Android系统的要求是Android4.0及以上版本。
(如有转载请在文首注明出处,AnYuanLzh:http://blog.csdn.net/anyuanlzh/article/details/18367941)
以上是关于设计好用的触控操作手势的主要内容,如果未能解决你的问题,请参考以下文章