创建自定义控件3-可交互性

2024-03-31 08:48

本文主要是介绍创建自定义控件3-可交互性,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

绘制UI仅仅是创建自定义视图的一部分。除此之外,你还需要以一种非常接近现实世界行为的方式来响应用户的输入。所有的对象都应该表现得像现实世界的对象那样。例如,图片不应该突然消失后又出现在别的地方,因为现实中的物体是不会那样的。合乎情理的做法是它应该从一个位置移动到另一个位置。 用户要么体验到UI中精细的操作,要么仅仅感觉到只是界面,相比较而言前者模拟的现实世界会获得最好的用户体验。例如,当用户在操作UI的时候,他们一旦感到界面的滑动响应延迟,将会感到烦躁而疯狂的滑动屏幕。

这篇文章展示了如何结合Android框架的特点来增添现实世界的行为到你所定制的视图中。

处理输入手势-Handle Input Gestures


跟许多其它的UI框架一样,Android也支持输入事件模型。用户的操作会转变成触发回调函数的事件,你可以重写这个回调函数来定制你的应用如何响应用户。在Android系统中最常用的输入事件是触摸事件,它会触发onTouchEvent(android.view.MotionEvent),重写该方法可以处理该事件:

1
2
3
4
@Override   
public boolean onTouchEvent(MotionEvent event) {    
return super.onTouchEvent(event);  
}

触摸事件本身并不是特别的有用。现在的可触摸UI可以接受许多种手势动作的交互,如 轻拍、拉、推、摇动和缩放。Android系统提供了GestureDetector类,将基本的触摸事件转变成各种不同的手势动作。 通过实现GestureDetector.OnGestureListener接口来构造一个GestureDetector的一个实例。如果你仅仅只是想处理少部分的手势动作,你可以选择继承GestureDetector.SimpleOnGestureListener而不用去实现GestureDetector.OnGestureListener接口。例如,下面的代码就是创建了一个继承GestureDetector.SimpleOnGestureListener的类并重写了onDown(MotionEvent)方法。

1
2
3
4
5
6
7
class mListener extends GestureDetector.SimpleOnGestureListener {   
@Override   
public boolean onDown(MotionEvent e) {       return true;   
}
}
mDetector = new GestureDetector(PieChart.this.getContext(),new mListener());

不管你是否使用了GestureDetector.SimpleOnGestureListener类,你都必须要实现onDown()方法并返回true。这一步是必须的因为所有的触摸操作都从onDown() 方法中的事件开始。如果你在onDown()方法中返回false,就像GestureDetector.SimpleOnGestureListener所设计的那样,系统会认为你不需要其它的手势操作,那么GestureDetector.OnGestureListener接口的其余方法都不会被调用。唯一能够将onDown()方法返回false的情况就是你真的想忽略所有的手势操作。一旦你实现了GestureDetector.OnGestureListener接口并且创造了GestureDetector类的一个实例,你就可以用GestureDetector类来完成你在 onTouchEvent()方法中接收的触屏事件。

 123456789
10
11
@Override
public boolean onTouchEvent(MotionEvent event) {   
boolean result = mDetector.onTouchEvent(event);   
if (result) {       
if(event.getAction()==MotionEvent.ACTION_UP){           
stopScrolling();           
result = true;       
}   
}   return result;
}

当你想执行onTouchEvent()方法中的触摸事件而并不想把它当作手势操作的一部分,那就要返回false。你可以执行你自定义的检测手势操作的代码。

创建让人感觉合理的操作-Create Physically Plausible Motion

手势动作是控制触摸屏设备的一种很强有力的方式,但是它会违背人的直觉而让人难以记住,除非它让人得到合理的结果。滑动手指就是一个很好的例子,用户用一根手指快速的在屏幕上滑动然后抬起。只有在UI的响应速度跟得上用户快速的滑动屏幕的频率的时候,这个手势操作才是有意义的,就像用户在推动一个飞轮并想让它旋转起来。

然而,模拟一种飞轮的感觉也是不平凡的。要想得到一个正确的飞轮运转模型是需要大量的物理和数学验证的。庆幸的是,Android提供了帮助类来模拟它以及别的操作行为。Scroller 类是处理具有飞轮风格手势操作的基类。 开始实现滑动操作时,要调用fling()并传入初始的速率和在X轴和Y轴上滑动的最小值和最大值。根据这个速率的值,你就可以用该值并通过GestureDetector类来为你计算。

1
2
3
4
5
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {   
mScroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY);   
postInvalidate();
}

提示: 尽管通过GestureDetector类计算出的速率在理论上是精确的,但是许多开发人员都感到用这个值会让滑动的动画太快。常用的办法就是将X和Y方向的速率除以4到8之间的某一个值。

调用fling()方法会建立滑动操作的物理模型。接下来,你需要适时的调用 Scroller.computeScrollOffset() 方法来更新Scroller类的数据。computeScrollOffset() 方法通过读取当前的时间并用物理模型计算当前的X坐标和Y坐标来更新Scroller对象的内部状态调用getCurrX() 和getCurrY()方法可以获取最新的X坐标和Y坐标。 大部分的视图通过直接调用scrollTo()方法改变Scroller对象的X坐标和Y坐标的值。但是图表是有一点不一样的,它用当前Y轴的坐标来设定图表的张开角度。

1
2
3
4
if (mScroller.isFinished()) {mScroller.computeScrollOffset();setPieRotation(mScroller.getCurrY());
}

Scroller类能为你计算出滚动轴的位置,但是它不能自动的为你的视图提供它们的坐标位置。你必须确保你获得并应用的坐标在正常情况下足以能让滚动动画看起来流畅。这里有两种方法可以实现:

    • 为了能重绘视图,在调用fling()之后要调用postInvalidate()。这种技术需要你每次在补偿滚动轴的变化时要在onDraw()方法中计算滚动轴的变化并调用postInvalidate()方法。
    • 建立一个ValueAnimator来动态模拟滑动动作持续的状态,然后调用addUpdateListener()来添加一个监听者进行动画的更新。

图表用的就是第二种方法。这种方法在创建的时候略微会显得更加复杂,但是它工作起来会跟动画系统配合得更密切而且不需要可能不必要的无效视图。它的缺憾就是在低于API11的版本上ValueAnimator是不可用的,所以这种方法是不能用在低于Android3.0系统的设备上的。

提示:ValueAnimator虽然在低于API11的版本不可用,但是你仍然可以在你的应用程序中使用这个类并标上API版本过低。在程序运行的时候你必须确保检查了当前的API版本,如果当前的API版本低于11,在视图动画系统中就要忽略这些调用。

 123456789
10
11
12
13
14
mScroller = new Scroller(getContext(), null, true);
mScrollAnimator = ValueAnimator.ofFloat(0,1);
mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {           
@Override           
public void onAnimationUpdate(ValueAnimator valueAnimator) {               
if(mScroller.isFinished()){                   
mScroller.computeScrollOffset();
setPieRotation(mScroller.getCurrY());               
} else {                   
mScrollAnimator.cancel();                   
onScrollFinished();               
}           
}       
});

让你的界面流畅地转换

用户期望现代的UI能流畅的在状态之间转换。UI元素的淡入淡出会取代直接的出现和消失。各种操作都会按照自然的方式开始和结束而不是突然的启动和停止。在Android3.0系统中引入的property animation framework框架,会让流畅的转换变得简单。 在使用动画系统时,每一个视图属性的改变都将会影响到视图的外观,所以不要直接去改变视图的属性。取而代之的是,你可以用ValueAnimator来实现你对视图属性的改变。在下面的例子中,修改当前在图表中选定的饼图饼片会导致整个图表旋转,以便让你选择的点集中在选定的切片上。ValueAnimator 会在一个短暂的时间内实现旋转的改变,而不是突然地改变旋转的状态。

1
2
3
4
mAutoCenterAnimator = ObjectAnimator.ofInt(PieChart.this,"PieRotation",0); 
mAutoCenterAnimator.setIntValues(targetAngle);
mAutoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION);
mAutoCenterAnimator.start();

如果你想改变基本的View 中的一个属性值,不如去改变视图动画,因为视图中有一个嵌入的ViewPropertyAnimator类,它对同步的多属性的动画做了优化。例如:

1
animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();

这篇关于创建自定义控件3-可交互性的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/863925

相关文章

python如何创建等差数列

《python如何创建等差数列》:本文主要介绍python如何创建等差数列的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python创建等差数列例题运行代码回车输出结果总结python创建等差数列import numpy as np x=int(in

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam

怎么用idea创建一个SpringBoot项目

《怎么用idea创建一个SpringBoot项目》本文介绍了在IDEA中创建SpringBoot项目的步骤,包括环境准备(JDK1.8+、Maven3.2.5+)、使用SpringInitializr... 目录如何在idea中创建一个SpringBoot项目环境准备1.1打开IDEA,点击New新建一个项

如何使用Maven创建web目录结构

《如何使用Maven创建web目录结构》:本文主要介绍如何使用Maven创建web目录结构的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录创建web工程第一步第二步第三步第四步第五步第六步第七步总结创建web工程第一步js通过Maven骨架创pytho

MySQL 用户创建与授权最佳实践

《MySQL用户创建与授权最佳实践》在MySQL中,用户管理和权限控制是数据库安全的重要组成部分,下面详细介绍如何在MySQL中创建用户并授予适当的权限,感兴趣的朋友跟随小编一起看看吧... 目录mysql 用户创建与授权详解一、MySQL用户管理基础1. 用户账户组成2. 查看现有用户二、创建用户1. 基

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

如何自定义一个log适配器starter

《如何自定义一个log适配器starter》:本文主要介绍如何自定义一个log适配器starter的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求Starter 项目目录结构pom.XML 配置LogInitializer实现MDCInterceptor

Macos创建python虚拟环境的详细步骤教学

《Macos创建python虚拟环境的详细步骤教学》在macOS上创建Python虚拟环境主要通过Python内置的venv模块实现,也可使用第三方工具如virtualenv,下面小编来和大家简单聊聊... 目录一、使用 python 内置 venv 模块(推荐)二、使用 virtualenv(兼容旧版 P