文档章节

手势模型和Angular Material的实现

予沁安
 予沁安
发布于 2015/04/14 23:11
字数 1620
阅读 181
收藏 2

iPhone的出现让手势操作大为流行,也使得手势编程成为开发人员的挑战。 拟物设计也把手势编程纳入在内,大概也想制定一个在交互模型标准。现阶段因为MD还在预发布阶段,因此还只实现了单点手势(一个指头),可是已经有足够的 东西值得学习,无论对我们应用还是自己设计手势编程都是大有裨益。

Angular Material有两个手划控件mdSwipeLeft和mdSwipeRight,然而真正的代码支持却不在这两个控件的定义中,而是在核心代码中,文 件位置src\core\services\gesture\gesture.js这里也就是我们深入研究手势实现的地方。

基本屏幕事件

做过界面的人都熟悉mousedown, mouseup, mousemove等事件,很多后台函数多与这些事件绑定,从而能够与用户交互。但是这些事件都有些单薄而僵硬,手势事件却更友好和人性化,这也是其大受欢迎的根本原因。
手势事件不是空中楼阁,它们本身是需要这些基本事件的支持,这些基本屏幕事件也就成为了手势模型的一个组成部分,成为最底的一层。

这些事件首先被划分为三类,说是三类,理解成三个事件更为恰当,它们与手指与屏幕的交互一一对应:开始事件就是手指按下屏幕;移动事件就是手指在屏幕移动;结束事件就是手指离开屏幕。非常简单而直观。
从下面MD对这三类事件的定义,我们也可以看到每类事件中的变体大都与设备的不同有关而不是真正的不同事件,如鼠标的按下,和手指的按下。这也是我上面说的把它们理解为三个事件更为恰当。

  • START_EVENTS =>'mousedown touchstart pointerdown';
  • MOVE_EVENTS => 'mousemove touchmove pointermove';
  • END_EVENTS => 'mouseup mouseleave touchend touchcancel pointerup pointercancel';

手势归纳

基本事件都是瞬间事件,不存在延时和逻辑判断,按下就是按下,松开就是松开;这也是称之为基本事件的原因。
而手势却恰恰相反,

  • 手势是综合事件,如滑动手势,直观的感觉就是手指按下快速向左(右)滑动,并同时松开手指,这整个过程完成才是一个滑动手势。
  • 手势还有逻辑判断,还是滑动手势,不仅仅要在以上的全过程之后才激发,手指的还要超过一定的速度才能算是滑动手势。

因此,可以把手势看作在基本事件之上的一个封装,在MD的实现也是用GestureHandler的函数还侦听基本事件然后作出综合处理。

侦听

这里是MD绑定基本事件的代码:

angular.element(document)
  .on(START_EVENTS, gestureStart)
  .on(MOVE_EVENTS, gestureMove)
  .on(END_EVENTS, gestureEnd)

MD移动事件的侦听处理函数:

function gestureMove(ev) {
  if (!pointer || !typesMatch(ev, pointer)) return;
  updatePointerState(ev, pointer);
  runHandlers('move', ev);
}

其它两个(开始和结束事件)都与此类似,只不过有更多的处理过程。这个因为简单,可以用来好好分析关键过程。我们可以看到,这个侦听函数的关键一步 就是调用处理器(runHandler)。这个函数内部并不复杂,只是简单的遍历预存处理器,然后调用该处理器定义的对应的基本事件处理器。这个处理器就 是手势处理器,它会分析归纳基本事件当条件满足时触发手势事件。

手势处理器$$MdGestureHandler

MD用工厂(factory)的方式定义了手势处理器的模板(或者可以理解为基类帮助理解),这个factory名称就是$$MdGestureHandler,为了便于理解,我们把它分解成三部分来看。

基本屏幕事件处理

第一部分:4个方法,分别与三类基本屏幕事件对应(cancel是辅助方法),也是用来分别处理三类屏幕事件的,上面的runHandler就是调用的源头。

start: function(ev, pointer) {
	if (this.state.isRunning) return;
	var parentTarget = this.getNearestParent(ev.target);
	var parentTargetOptions = parentTarget && parentTarget.$mdGesture[this.name] || {};

	this.state = {
	isRunning: true,
	options: angular.extend({}, this.options, parentTargetOptions),
	registeredParent: parentTarget
	};
	this.onStart(ev, pointer);
	},
move: function(ev, pointer) {
	if (!this.state.isRunning) return;
	this.onMove(ev, pointer);
	},
end: function(ev, pointer) {
	if (!this.state.isRunning) return;
	this.onEnd(ev, pointer);
	this.state.isRunning = false;
	},
cancel: function(ev, pointer) {
	this.onCancel(ev, pointer);
	this.state = {};
},
优化的屏幕事件

第二部分:4个内部事件,也是基本与以上4个方法对应,并在4个方法中适当的时机触发,可以看作是对原始基本事件 的梳理之后的重新抛出。 你如果创建自己的手势处理器,要做的也就是重载这4个事件。从以下代码我们也可以看到,MD为每一个事件给出了空实现(`angular.noop'), 目的就是为了让自定义处理器自己重载实现。

onStart: angular.noop,
onMove: angular.noop,
onEnd: angular.noop,
onCancel: angular.noop,
手势的触发

第三部分:也是最后最关键的一个方法,手势事件的触发dispatchEvent。自定义的手势处理器最终都是要调用这个方法来触发手势事件。大部分触发时机都在onEnd中,当是不是必须的,要根据你具体的手势的含义来定。
dispatchEvent的实现:

dispatchEvent: dispatchEvent,
...
/*
* NOTE: dispatchEvent is very performance sensitive. 
*/
function dispatchEvent(srcEvent, eventType, eventPointer, /*original DOMEvent */ev) {
	eventPointer = eventPointer || pointer;
	var eventObj;
	
	if (eventType === 'click') {
	  eventObj = document.createEvent('MouseEvents');
	  eventObj.initMouseEvent(
	    'click', true, true, window, ev.detail,
	    ev.screenX, ev.screenY, ev.clientX, ev.clientY, 
	    ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey,
	    ev.button, ev.relatedTarget || null
	  );
	
	} else {
	  eventObj = document.createEvent('CustomEvent');
	  eventObj.initCustomEvent(eventType, true, true, {});
	}
	eventObj.$material = true;
	eventObj.pointer = eventPointer;
	eventObj.srcEvent = srcEvent;
	eventPointer.target.dispatchEvent(eventObj);
}

手势实例解析

手势内部实现过程虽然较为复杂,以上的流程解析也是为了更好的理解从而有个直观的感觉。到了每一个手势的实现时,真 正用到的却不算多,主要就是那4个优化的事件onStart, onMove, onEnd, onCancel和一个触发的方法'dispatchEvent`。我们来看看一些手势实例,亲身感受一下,良好建模以后的手势实现。

滑动手势 - Swipe
屏幕事件 触发条件 触发事件
[无]

按下

移动

移动

移动

移动

松开 超过最低速度和位移 $md.swiperight
[无]

拖动手势 - Drag
屏幕事件 触发条件 触发事件
[无]

按下

移动

移动 当前触点与起点位移超过阀值 $md.dragstart
移动
$md.drag
移动
$md.drag
松开
$md.dragend
[无]

© 著作权归作者所有

共有 人打赏支持
予沁安

予沁安

粉丝 95
博文 23
码字总数 31905
作品 3
其他
架构师
私信 提问
[Angular Material完全攻略] Day 02 - 环境设定 & 安装 & Hello World

今天我们将开始正式迈入Angular Material的世界,要学习使用Angular Material打造高品质及高质感的网页,当然要从安装Angular Material套件开始,本篇文章就来介绍基本的Angular Material安装...

readilen
2018/05/21
0
0
Angular 的 Material Design 风格框架 - Angular Material

Material Design for Angular 是 Angular 官方团队开发的基于最新版本 Angular 的 Material Design 风格的框架,可和 Nest.js 搭配使用做全栈开发。 针对 Angular 1 版本的实现 https://www....

匿名
2018/05/15
0
0
AngularJS 的 Material Design 风格框架 - AngularJS Material

AngularJS Material 是 AngularJS 框架的谷歌 Material Design 标准的实现。AngularJS Material 包含一组丰富的、可重用、经过充分测试并可访问的 UI 组件。 针对 Angular 2 或更高版本的实现...

匿名
2018/05/15
0
0
[Angular Material完全攻略] Day 01 - 开始 & 简介

转载 从Angular第2版正式release后,根据全球最大工程师讨论区StackOverflow的统计,从2016开始的Angular讨论度就不断窜升,甚至超越了React,直到了2017年,甚至摆脱了前一代Angularjs的阴影...

readilen
2018/05/21
0
0
Angular 的 Material Design 风格框架 material2 6.3.2

Angular 的 Material Design 风格框架 material2 6.3.2 已发布。 本次更新内容主要是 Bug 修复,修复各种组件存在的一些问题。 源码下载和更新详情可查看 https://github.com/angular/mater...

局长
2018/07/05
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS7 下安装 Nginx

1、添加Nginx存储库 要添加CentOS 7 EPEL仓库,请打开终端并使用以下命令 yum install epel-release 2、安装Nginx 现在Nginx存储库已经安装在您的服务器上,使用以下yum命令安装Nginx yum i...

Oo若离oO
11分钟前
0
0
漏洞防御与修复工作

漏洞管理工作是企业安全建设必不可少的一环,在风险管理工作中,漏洞管理能够防患于未然,企业对漏洞管理有着广泛的基础建设和实践经验。但随着攻防技术的发展,传统漏洞管理的安全技术和管理...

linuxprobe16
今天
1
0
MicroPython技术及应用前景

1 Micropython技术是什么? MicroPython极精简高效的实现了Python3语言。它包含Python标准库的一小部分,能在单片机和受限环境中运行。 1.1 MicroPython发展 由剑桥大学的理论物理学家乔治....

bodasisiter
今天
5
0
跟我学Spring Cloud(Finchley版)-13-通用方式使用Hystrix

本节详细讲解使用Hystrix的通用方式。 简介 Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。Hystrix主要...

周立_ITMuch
今天
2
0
🛠️Hanjst/汉吉斯特更新加JavaScript运行时优化等

这是 Hanjst/汉吉斯特 发布以来的首个主要升级更新版本。这次的主要升级更新的内容包括移除HTML Comments注释行, 优化在 Hanjst include模板文件时的JavaScript运行时环境。 Hanjst 在设计和...

wadelau
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部