设为首页 收藏本站
查看: 1245|回复: 0

Windows Phone 7 开发探索笔记2——触控操作之Manipulation

[复制链接]

尚未签到

发表于 2015-5-8 09:56:10 | 显示全部楼层 |阅读模式
  在上篇文章中介绍了底层的触控编程接口,本文将讲解Silverlight for Windows Phone中的高级触控编程接口,与之相关的是定义在UIElement中的
  ManipulationStarted,ManipulationDelta和ManipulationCompleted事件。
  一.Manipulation相关事件
  这3个事件并不是单独来处理每个手指的触控信息的,它们将所有手指的平移和缩放操作进行了整合。由于这3个事件都是在UIElement类中定义的,都是基于具体的元素的,而非应用程序级别的事件,所以我们可以为任何UI元素添加对这些事件的处理,比如ListBox,Canvas,Rectangle等等。下面的XAML代码是在一个Rectangle元素中添加了对这3个事件的处理程序:

DSC0000.gif DSC0001.gif 代码


            
               
                    
                        
                    
               
            
  从它们的名字就可以看出它们被触发的顺序:先是一个ManipulationStarted事件, 然后是0个或多个ManipulationDelta事件, 最后是一个ManipulationCompleted事件。在它们对应的Code-Behind文件中相应的事件处理程序的定义如下:

代码

void rectangle_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
void rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
void rectangle_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
  我们在程序中重点使用的就是这3个类型的事件参数,它们的类型虽有不同,但却有几个相同的属性:

  • OriginalSource:类型为object,它是定义在RoutedEventArgs类中的,通过它我们可以获取到触发这个事件的原始对象。


  • ManipulationContainer:类型为UIElement,可以获取到定义当前这个触控操作坐标的对象(通常与OriginalSource是相同的)。


  • ManipulationOrigin:类型为Point。获取操作的起源坐标,即手指触摸到的那一点的坐标,此坐标的数值就是相对于ManipulationContainer对象左上角的。如果有两个或多个手指在操作一个元素,那么ManipulationOrigin 属性会给出多个手指的平均坐标。


  • Handled:类型为bool,是用来指示路由事件在路由过程中的事件处理状态的。如果我们不想让当前事件沿着Visual Tree继续传播可以将它设置为true。有关路由事件请参见路由事件。
  在接下来的文章中我会通过一个例子介绍所有与Manipulation事件相关的内容。首先来看一下程序的Logic Tree和效果图:
DSC0002.jpg DSC0003.jpg
  下面的代码演示了这3个事件中相同的属性:

代码

        void rectangle_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            Debug.WriteLine("Rectangle ManipulationStarted");
            Debug.WriteLine("OriginalSource: " + (e.OriginalSource as FrameworkElement).Name);
            Debug.WriteLine("ManipulationContainer: " + (e.ManipulationContainer as FrameworkElement).Name);
            Debug.WriteLine("ManipulationOrigin: " + "X: " + e.ManipulationOrigin.X.ToString() + " Y: " + e.ManipulationOrigin.Y.ToString() + "\n");
        }
        void rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            Debug.WriteLine("Rectangle ManipulationDelta");
            Debug.WriteLine("OriginalSource: " + (e.OriginalSource as FrameworkElement).Name);
            Debug.WriteLine("ManipulationContainer: " + (e.ManipulationContainer as FrameworkElement).Name);
            Debug.WriteLine("ManipulationOrigin: " + "X: " + e.ManipulationOrigin.X.ToString() + " Y: " + e.ManipulationOrigin.Y.ToString() + "\n");
        }
        void rectangle_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            Debug.WriteLine("Rectangle ManipulationCompleted");
            Debug.WriteLine("OriginalSource: " + (e.OriginalSource as FrameworkElement).Name);
            Debug.WriteLine("ManipulationContainer: " + (e.ManipulationContainer as FrameworkElement).Name);
            Debug.WriteLine("ManipulationOrigin: " + "X: " + e.ManipulationOrigin.X.ToString() + " Y: " + e.ManipulationOrigin.Y.ToString() + "\n");
        }  下面是输出结果:
DSC0004.jpg
  和上面说过的顺序一样。此次操作触发了3次ManipulationDelta事件,由于手指(这里是鼠标,因为是在模拟器上操作的)在屏幕上移动了,所以每次的ManipulationOrigin值都是不一样的。同时我们还可以看到OriginalSource和ManipulationContainer是相同的。
  二.理解构建在单个元素上的一系列操作
  和底层的触控API Touch.FrameReported为每个特定的手指都关联一个特定的Id不同,Manipulation相关的事件是基于UI元素的,所以这些事件不需要这个Id。当多个手指触摸一个元素时它们会被转化为一系列的Manipulation事件,当不同的手指在不同的元素上时则会产生两个系列的Manipulation事件,这两个系列是独立的。当然它们可以通过ManipulationContainer属性来区分。例如:将一个手指放在一个元素上,首先一个ManipulatedStarted事件会被触发,如果手指移动那么就会触发ManipulationDelta事件。保持这个手指不动,将另一个手指放在相同的元素上不会再触发一个新的ManipulatonStarted 事件。但如果此时我将另一个手指放在其他的元素上,则会触发那个元素的ManipulationStarted事件。
  如果你想在单个元素上跟踪不同手指的触控信息,那就应该使用Touch.FrameReported事件,关于此事件的内容可以参见我的上一篇文章。
  三.详解3种Manipulation事件参数
  1.首先来看最简单的ManipulationStartedEventArgs类:除了上面说的4种共有的属性外,它还有一个Complete方法,它是用来告诉系统将ManipulationStarted事件结束掉,这样的话即使你的手指在屏幕上移动ManipulationDelta也不会被触发。
  2.接下来是ManipulationDeltaEventArgs类:除了共有属性外,这个类还包含2个ManipulationDelta类型的属性:CumulativeManipulationDeltaManipulation。ManipulationDelta类包含2个Point类型的属性:ScaleTranslation
  Scale和Translation属性帮我们将一个或多个手指在某个元素上的复合动作解析成了元素自身的移动和尺寸变化。Scale表示的是缩放因子,Translation表示的是平移的距离。我们用一个手指操作时就可以改变Translation的值,但如果要改变Scale需要用两个手指操作。当你手指在一个元素上移动时,手指所在的新位置和原来位置的差值就会反映在Translation中。如果是用两个手指进行缩放,原来手指之间的距离与缩放后手指间距离差值会反映在Scale中。有一点需要注意:如果我们没有对元素进行缩放操作,Scale的值是(0, 0),我不知道这是不是Silverlight for Windows Phone的一个Bug,按理说如果没有缩放操作,默认的值应该是(1, 1)。
  下面来说CumulativeManipulation属性和DeltaManipulation属性的区别:虽然这两个属性都包含Scale和Translation。但CumulativeManipulation中的值是从ManipulationStarted事件开始到当前事件为止累加得到的(通过属性的名字就可以看出来),而DeltaManipulation中的值是本次ManipulationDelta事件相对于上一次ManipulationDelta或ManipulationStarted事件而言的,是单次的改变。
  除了CumulativeManipulation和DeltaManipulation属性,ManipulationDeltaEventArgs类中还有Complete方法,它的作用和ManipulationStarted中Complete方法一样,都是通知系统当前的操作结束,调用此方法后即便手指在元素上移动也只会触发一次ManipulationDelta事件,本系列Manipulation操作中不会再有后续的ManipulationDelta事件被触发(但可以触发ManipulationCompleted事件)。
  另外,ManipulationDeltaEventArgs类中还有一个IsInertial属性和Velocities属性,不过这两个属性好像并不能提供有用的信息,在我的测试过程中它们始终是False和(0,0)。
  3.最后是ManipulationCompletedEventArgs类型:除了共有属性外,还包含下面3个属性:

  • FinalVelocities:类型和ManipulationDeltaEventArgs类中的Velocities一样,都是ManipulationVelocities,通过它可以获取手指离开屏幕时的速度。
  • IsInertial:类型为bool,和ManipulationDeltaEventArgs类中的IsInertial一样(IsInertial属性在后面会详细说明)。
  • TotalManipulation:类似于ManipulationDeltaEventArgs类的CumulativeManipulation,类型也是ManipulationDelta,它是从ManipulationStarted事件到ManipulationCompleted事件全过程的累加值。
  四.完整实例
  我在上述程序中的Rectangle元素的RenderTransform属性中添加了一个TranslateTransform变换。并在这个Rectangle元素的ManipulationDelta事件处理程序中对TranslateTransform进行了操作,使得这个矩形可以在屏幕上移动,同时将所能获取到的信息输出到Output窗口,下面是代码:

代码

        void rectangle_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            Debug.WriteLine("Rectangle ManipulationStarted\n");
        }
        void rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            this.translation.X += e.DeltaManipulation.Translation.X;
            this.translation.Y += e.DeltaManipulation.Translation.Y;
            Debug.WriteLine("Rectangle ManipulationDelta");
            Debug.WriteLine("Rectangle Translation X:" + e.DeltaManipulation.Translation.X + " Rectangle Translation Y:" + e.DeltaManipulation.Translation.Y);
            Debug.WriteLine("Rectangle Cumulative X:" + e.CumulativeManipulation.Translation.X + " Rectangle Cumulative  Y:" + e.CumulativeManipulation.Translation.Y);
            Debug.WriteLine("LinearVelocity X:" + e.Velocities.LinearVelocity.X + " LinearVelocity Y:" + e.Velocities.LinearVelocity.Y + " IsInertial:" + e.IsInertial + "\n");
        }
        void rectangle_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            Debug.WriteLine("Rectangle ManipulationCompleted");
            Debug.WriteLine("Rectangle Total Translation X:" + e.TotalManipulation.Translation.X + " Rectangle Total Translation Y:" + e.TotalManipulation.Translation.Y);
            Debug.WriteLine("FinalVelocities X:" + e.FinalVelocities.LinearVelocity.X + " FinalVelocities Y:" + e.FinalVelocities.LinearVelocity.Y + " IsInertial: " + e.IsInertial + "\n");
        }  在上面代码的rectangle_ManipulationDelta方法中,我分别将Translation的X和Y赋给了TranslateTransform变换的X和Y,以保证矩形可以随意移动。下面是模拟器和输出窗口的截图:
DSC0005.jpg DSC0006.jpg
DSC0007.jpg
  注意上图中ManipulationCompleted事件参数中的FinalVelocities数值很大,这是因为我当时移动矩形的速度非常快,如果是很慢的移动它,那么这个数值将变为0,同时IsInertial属性为False。另外,如果在ManipulationDelta的事件处理程序中调用了事件参数的Complete方法,则移动矩形时只能一下一下地移动,因为只会触发一次ManipulationDelta事件,并且ManipulationCompleted事件参数中的FinalVelocities属性会抛出NullReferenceException异常。
  五.IsInertial属性
  在WPF中,通过设置ManipulationInertiaStartingEventArgs参数,系统会在手指离开屏幕后通过算法来模拟惯性效果,即触发额外的ManipulationDelta事件。而在Silverlight for Windows Phone中并不支持这个特性。在WPF中,ManipulationDelta和ManipulationCompleted事件参数中的IsInertial属性本来是用来说明当前事件是否是在惯性效果发生期间被触发的,而在Silverlight for Windows Phone中,ManipulationDelta事件参数的IsInertial属性总是False。即便在快速移动时,ManipulationCompleted事件中的IsInertial为True,也并没有出现惯性效果,只是移动的过程比较流畅,手指抬起时矩形元素还是立刻就停止了移动。所以,我认为ManipulationDelta和ManipulationCompleted事件参数中的IsInertial属性没有太大的参考价值。如果想在Silverlight for Windows Phone中模拟惯性效果,我们可以借助ManipulationCompleted事件参数中的FinalVelocities属性来实现。
  好了,关于Windows Phone 7中的高级触控编程接口就介绍这么多,下一篇文章会介绍与手势相关的触控操作。
  六.下载示例代码:
  

WindowsPhoneManipulationDemo.zip  如果大家喜欢我的文章,请点击“推荐”,谢谢!

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-64888-1-1.html 上篇帖子: Windows Phone 7 开发探索笔记6——页面间传值 下篇帖子: 人人网 Windows Phone 7 应用开发起步
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表