【注】:这篇文章中的内容都以这张图来讲解分发机制,其中A、B、C都是ViewGroup,它们的层次关系为:A为根布局,B为二级子布局,C为三级子布局,其中C布局中包含一个Button按钮,即A包含B,B包含C,C包含Button。

好了,废话少说。先来讲下今天的三位主角吧。

1、dispatchTouchEvent - 分发事件,默认为false。true:取消事件,不继续向下分发,false:向下分发事件

2、onInterceptTouchEvent - 拦截事件,默认为false。true:拦截事件,自身的onTouchEvent()方法消费,false:事件继续向下传递

3、onTouchEvent - 处理事件,默认为false,true:消费事件,false:不消费事件,向上层传递让上层处理。【注】如果发生了拦截,那么如果该层不处理则会继续向上传递,让上层处理。如果过程中没有发生处理,则事件分发到底层后将一直向上层传递至Activity,在Activity的onTouchEvent()中处理。【注】如果在设置了setOnClickListener(…)的View或Viewgroup中,返回true则消费事件,会触发onClick事件,如果返回false,则不会触发onClick事件

这里借用网上的两张图片来增加理解:

1、在没有做任何处理,也即默认情况下,触摸屏幕发生的一系列事件分发过程:

如果DOWN事件没有被消费,则后续的MOVE/UP事件将不会传递过来,直接在Activity层处理

2、如果子View消费了事件,则事件的分发过程为:

上面这三个方法就是负责Android中当用户触摸屏幕时事件的分发与处理。在Android中,事件的分发是遵循这样一套机制的:当用户触摸到屏幕时,也就是触摸到Activity界面,当Activity中的dispatchTouchEvent()方法允许分发时,这时这个触摸事件就会先出现在根布局这个ViewGroup中,然后再向里层的ViewGroup或View传递,也就是Activity->RootView->子ViewGroup->…..->View。

如图:

下面我们通过几个示例来看看事件分发到底是怎样的?

我们按最上面那个图布局好后,然后分别实现A、B、C中的dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent()三个方法,然后实现Button中的dispatchTouchEvent()、onTouchEvent()两个方法,再用Log分别在各自的方法以这种形式打印出来: Log.v(“zxy”,”C—–>onInterceptTouchEvent”);

【注】:只有ViewGroup中才有onInterceptTouchEvent()拦截事件方法,View中只有分发事件和处理事件这个两个方法。

在默认情况下,我们点击屏幕上的Button

在此之前,要先说个概念,我们知道用户触摸到屏幕时候,会触发一系列事件,顺序为:Down->(Move….)->Up,这里为什么要给Move打括号呢?因为在此过程中,有可能用户只点击然后抬起手指,有可能点击后又移动了多次,所以Move的次数是不确定的,但是只要触摸到屏幕,一定会有Down和Up事件,这里我们假设在点击过程中不移动手指,所以只产生Down和Up两个事件。

所以触摸一次既然有两个事件Down->Up:

1、Up的分发也是取决于Down是否分发,如果Down事件在B层的dispatchTouchEvent()方法返回true,也即取消事件停止分发,那么后续的Move事件、Up事件也只能到达B层,并在B层取消分发。假如我们在A层中的dispatchTouchEvent()方法返回true,也就是取消事件停止分发,那么Down事件会在A层中取消事件,Up事件也会在A层中取消事件(假设我们手指不移动只产生down和up两个事件),所以Log只有Down和Up两个事件并都在A层取消分发,Log如下:

-------------------Down

08-17 21:39:01.447 2661-2661/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 21:39:01.447 2661-2661/? V/zxy﹕ A----->dispatchTouchEvent

-------------------Up

08-17 21:39:01.540 2661-2661/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 21:39:01.540 2661-2661/? V/zxy﹕ A----->dispatchTouchEvent1

2

3

4

5

6

2、Down事件无论在哪一层中被拦截即onInterceptTouchEvent()返回true,那么后续的Move事件、Up事件都不会被下发,都只能在Activity层处理。假如我们在A层中onInterceptTouchEvent()返回true,我们可以看打印的Log中Down事件的分发过程,其余事件都停留在Activity层,Log如下:

-------------------Down

08-17 21:28:28.510 2557-2557/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 21:28:28.510 2557-2557/? V/zxy﹕ A----->dispatchTouchEvent

08-17 21:28:28.510 2557-2557/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 21:28:28.510 2557-2557/? V/zxy﹕ A----->onTouchEvent

08-17 21:28:28.510 2557-2557/? V/zxy﹕ Activity----->onTouchEvent

------------------Up

08-17 21:28:28.596 2557-2557/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 21:28:28.597 2557-2557/? V/zxy﹕ Activity----->onTouchEvent1

2

3

4

5

6

7

8

9

所以,我们清楚上面的概念后,下面的示例就比较好懂了

在默认情况下,我们分别在那几个方法中用Log打印,看看点击Button后事件传递的流程和各个方法执行的情况(假设手指没有移动),Log如下:

-------------------Down

08-17 21:58:03.585 2810-2810/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 21:58:03.585 2810-2810/? V/zxy﹕ A----->dispatchTouchEvent

08-17 21:58:03.585 2810-2810/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 21:58:03.585 2810-2810/? V/zxy﹕ B----->dispatchTouchEvent

08-17 21:58:03.585 2810-2810/? V/zxy﹕ B----->onInterceptTouchEvent

08-17 21:58:03.585 2810-2810/? V/zxy﹕ C----->dispatchTouchEvent

08-17 21:58:03.585 2810-2810/? V/zxy﹕ C----->onInterceptTouchEvent

08-17 21:58:03.585 2810-2810/? V/zxy﹕ Button----->dispatchTouchEvent

08-17 21:58:03.585 2810-2810/? V/zxy﹕ Button----->onTouchEvent

-------------------Up

08-17 21:58:03.677 2810-2810/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 21:58:03.677 2810-2810/? V/zxy﹕ A----->dispatchTouchEvent

08-17 21:58:03.677 2810-2810/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 21:58:03.677 2810-2810/? V/zxy﹕ B----->dispatchTouchEvent

08-17 21:58:03.677 2810-2810/? V/zxy﹕ B----->onInterceptTouchEvent

08-17 21:58:03.677 2810-2810/? V/zxy﹕ C----->dispatchTouchEvent

08-17 21:58:03.677 2810-2810/? V/zxy﹕ C----->onInterceptTouchEvent

08-17 21:58:03.677 2810-2810/? V/zxy﹕ Button----->dispatchTouchEvent

08-17 21:58:03.677 2810-2810/? V/zxy﹕ Button----->onTouchEvent1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

我可以看出,点击中间的Button后,首先是调用Activity中的dispatchTouchEvent()方法,因为这个方法默认返回值为false,所以往下分发,然后到了ViewGroup-A,在A中又往下分发到达B,在B中又往下分发到达C,在C中又往下分发到达Button,然后在Button中的onTouchEvent()消费事件,可能这里会有疑问?这里明明是默认情况下,没有发生拦截和onTouchEvent没有指定返回ture,怎么在Button那里就消费了呢?原因是像Button、ImageButton那样可点击的View在默认情况下onTouchEvent是返回ture的表示默认消费事件,而其它默认情况下不可点击的View或ViewGroup则返回false表示默认不消费事件。所以到达Button这层消费了事件就不会往上层传递了。

在B层中取消事件分发

即在B层的dispatchTouchEvent()方法返回true

打印的Log为:

-------------------Down

08-17 22:10:16.872 2923-2923/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 22:10:16.873 2923-2923/? V/zxy﹕ A----->dispatchTouchEvent

08-17 22:10:16.873 2923-2923/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 22:10:16.873 2923-2923/? V/zxy﹕ B----->dispatchTouchEvent

-------------------Up

08-17 22:10:16.974 2923-2923/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 22:10:16.974 2923-2923/? V/zxy﹕ A----->dispatchTouchEvent

08-17 22:10:16.974 2923-2923/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 22:10:16.974 2923-2923/? V/zxy﹕ B----->dispatchTouchEvent1

2

3

4

5

6

7

8

9

10

可以看到,在事件传递到B层后,事件就不能继续分发了,事件取消了

在B层拦截事件

在B层拦截事件后onTouchEvent()返回true,消费事件

-------------------Down

08-17 22:22:29.376 3039-3039/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 22:22:29.377 3039-3039/? V/zxy﹕ A----->dispatchTouchEvent

08-17 22:22:29.377 3039-3039/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 22:22:29.377 3039-3039/? V/zxy﹕ B----->dispatchTouchEvent

08-17 22:22:29.377 3039-3039/? V/zxy﹕ B----->onInterceptTouchEvent

08-17 22:22:29.377 3039-3039/? V/zxy﹕ B----->onTouchEvent

-------------------Up

08-17 22:22:30.309 3039-3039/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 22:22:30.309 3039-3039/? V/zxy﹕ A----->dispatchTouchEvent

08-17 22:22:30.309 3039-3039/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 22:22:30.309 3039-3039/? V/zxy﹕ B----->dispatchTouchEvent

08-17 22:22:30.309 3039-3039/? V/zxy﹕ B----->onTouchEvent1

2

3

4

5

6

7

8

9

10

11

12

13

可以看到,在B层如果拦截后,那么事件就到B层的onTouchEvent()方法中,同时消费该事件

在B层拦截事件后onTouchEvent()返回false,不消费事件,传递给上层处理

首先,因为刚刚在上面讲了,无论在哪个层发生了事件拦截,只有Down事件才会到达该层,而Move、Up事件则将停留在Activity层处理。

又因为该层发生了拦截,所以onTouchEvent()默认返回为false,所以Log如下:

08-17 22:29:01.714 3211-3211/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 22:29:01.715 3211-3211/? V/zxy﹕ A----->dispatchTouchEvent

08-17 22:29:01.715 3211-3211/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 22:29:01.715 3211-3211/? V/zxy﹕ B----->dispatchTouchEvent

08-17 22:29:01.715 3211-3211/? V/zxy﹕ B----->onInterceptTouchEvent

08-17 22:29:01.715 3211-3211/? V/zxy﹕ B----->onTouchEvent

08-17 22:29:01.715 3211-3211/? V/zxy﹕ A----->onTouchEvent

08-17 22:29:01.715 3211-3211/? V/zxy﹕ Activity----->onTouchEvent

------------------Up

08-17 22:29:01.802 3211-3211/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 22:29:01.802 3211-3211/? V/zxy﹕ Activity----->onTouchEvent1

2

3

4

5

6

7

8

9

10

11

从Log中可以看出,在B发生拦截后,该层如果不处理该事件,则会向上一层A传递,同时A默认返回为false,即不处理,再继续向上一层Activity传递,这时候到达顶层了,没有谁可以传递了,就在Activity中消费该事件。同时也可以看到无论哪一层发生拦截后Up事件只能停留在Activity层。

其它情况都默认,当事件到达Button层onTouchEvent()事件的处理

不消费事件,onTouchEvent()返回false

Log为:

因为Button层的onTouchEvent()方法不消费该事件,所以将往上层的父ViewGroup传递,直到消费事件为止

------------------Down

08-17 23:12:31.004 3659-3659/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ A----->dispatchTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ B----->dispatchTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ B----->onInterceptTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ C----->dispatchTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ C----->onInterceptTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ Button----->dispatchTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ Button----->onTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ C----->onTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ B----->onTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ A----->onTouchEvent

08-17 23:12:31.004 3659-3659/? V/zxy﹕ Activity----->onTouchEvent

------------------Up

08-17 23:12:31.137 3659-3659/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 23:12:31.137 3659-3659/? V/zxy﹕ Activity----->onTouchEvent1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

这里为什么Up事件一直在Activity层呢?因为Down事件分发过程中,如果View或ViewGroup没有对ACTION_DOWN事件进行消费,之后的其他事件也就不会传递过来了。

消费事件,onTouchEvent()返回true(默认情况下就会消费事件)

------------------Down

08-17 23:18:07.619 3783-3783/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 23:18:07.620 3783-3783/? V/zxy﹕ A----->dispatchTouchEvent

08-17 23:18:07.620 3783-3783/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 23:18:07.620 3783-3783/? V/zxy﹕ B----->dispatchTouchEvent

08-17 23:18:07.620 3783-3783/? V/zxy﹕ B----->onInterceptTouchEvent

08-17 23:18:07.620 3783-3783/? V/zxy﹕ C----->dispatchTouchEvent

08-17 23:18:07.620 3783-3783/? V/zxy﹕ C----->onInterceptTouchEvent

08-17 23:18:07.620 3783-3783/? V/zxy﹕ Button----->dispatchTouchEvent

08-17 23:18:07.620 3783-3783/? V/zxy﹕ Button----->onTouchEvent

------------------Up

08-17 23:18:07.728 3783-3783/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 23:18:07.728 3783-3783/? V/zxy﹕ A----->dispatchTouchEvent

08-17 23:18:07.728 3783-3783/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 23:18:07.728 3783-3783/? V/zxy﹕ B----->dispatchTouchEvent

08-17 23:18:07.728 3783-3783/? V/zxy﹕ B----->onInterceptTouchEvent

08-17 23:18:07.729 3783-3783/? V/zxy﹕ C----->dispatchTouchEvent

08-17 23:18:07.729 3783-3783/? V/zxy﹕ C----->onInterceptTouchEvent

08-17 23:18:07.729 3783-3783/? V/zxy﹕ Button----->dispatchTouchEvent

08-17 23:18:07.729 3783-3783/? V/zxy﹕ Button----->onTouchEvent1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

从Log中可以看出,在Button层消费了该事件后,将不再往上层传递

如果点击Button后,我们想让这个Down事件在C层处理完

因为我们想让这个Down事件在C层就处理完,所以在C层我们就拦截该事件设置onInterceptTouchEvent()返回值为true,并在C层onTouchEvent()中返回true消费事件。Log为:

-------------------Down

08-17 23:29:06.605 3979-3979/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 23:29:06.606 3979-3979/? V/zxy﹕ A----->dispatchTouchEvent

08-17 23:29:06.606 3979-3979/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 23:29:06.606 3979-3979/? V/zxy﹕ B----->dispatchTouchEvent

08-17 23:29:06.606 3979-3979/? V/zxy﹕ B----->onInterceptTouchEvent

08-17 23:29:06.606 3979-3979/? V/zxy﹕ C----->dispatchTouchEvent

08-17 23:29:06.606 3979-3979/? V/zxy﹕ C----->onInterceptTouchEvent

08-17 23:29:06.606 3979-3979/? V/zxy﹕ C----->onTouchEvent

------------------Up

08-17 23:29:06.705 3979-3979/? V/zxy﹕ Activity----->dispatchTouchEvent

08-17 23:29:06.706 3979-3979/? V/zxy﹕ A----->dispatchTouchEvent

08-17 23:29:06.706 3979-3979/? V/zxy﹕ A----->onInterceptTouchEvent

08-17 23:29:06.706 3979-3979/? V/zxy﹕ B----->dispatchTouchEvent

08-17 23:29:06.706 3979-3979/? V/zxy﹕ B----->onInterceptTouchEvent

08-17 23:29:06.706 3979-3979/? V/zxy﹕ C----->dispatchTouchEvent

08-17 23:29:06.706 3979-3979/? V/zxy﹕ C----->onTouchEvent1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

可以看到Down事件和Up事件在C层消费掉了,假如我们也设置了Button的onClickListener(…)方法,那么该onClick方法将不执行,因为事件在C层已经消费掉了

好了,Android的事件分发机制就讲完了,下面来梳理一下整个过程:

【注】:事件分发中,处理消费事件的方法onTouchEvent()只执行在两种情况下:

1、事件分发过程中没有事件拦截,到达最底层执行onTouchEvent方法消费事件,如果事件分发过程中没有事件拦截且最底层也没有消费该事件,则事件会向上层传递,如果一直没有ViewGroup消费事件则会在Activity中onTouchEvent()方法中消费。

2、事件分发过程中有事件拦截,则在发生事件拦截的这一层会执行onTouchEvent方法,把事件交给它处理,如果返回true则消费事件,如果为false它不消费事件,则往上一层的onTouchEvent方法中传递,如果上一层也不消费,则继续向上传递,当到达最顶层Activity,会执行Activity的onTouchEvent方法消费事件。

3、如果View或ViewGroup没有对 ACTION_DOWN 进行消费,之后的其他事件不会传递过来(也就在Activity层处理)

4、对于底层的View来说,有一种方法可以阻止父层的View截获touch事件,就是调用getParent().requestDisallowInterceptTouchEvent(true);方法。一旦底层View收到touch的action后调用这个方法那么父层View就不会再调用onInterceptTouchEvent了,也无法截获以后的action

5、像Button、ImageButton那样可点击的View在默认情况下onTouchEvent是返回ture的表示默认消费事件,而其它默认情况下不可点击的View或ViewGroup则返回false表示默认不消费事件

事件分发的流程:Activity——>ViewGroup1——>子ViewGroup2——>…——>子View

事件消费的流程:

1、onTouchEvent返回true:在该层消费

2、onTouchEvent返回false:子View或子ViewGroup——>…——>ViewGroup1——>Activity

android布局事件吗,Android事件分发机制相关推荐

  1. android布局界面点击事件在控件间的传递路径

    android的界面触摸事件分为三种,action_down,action_move,action_up这几个事件.这里我们主要说一下action_down事件的传递. 首先android的事件是从父 ...

  2. 下列不属于android布局的是( ),Android软件工程师笔试题(全选择题)【0-1年经验】...

    Android软件工程师笔试题,全选择题,适合0-1年经验的面试者. Android软件工程师笔试题 单选题(共35题) 1.退出 activity 对一些资源以及状态的操作保存,可以在生命周期的哪个 ...

  3. android布局的作用,Android UI布局经验总结

    如何在Android中动态设置颜色透明?10%20%到100% Android布局分析工具HierarchyView Android使用include/merge/ViewStub优化布局 List的 ...

  4. android布局加色,android – 如何以编程方式将LinearLayout添加背景颜色,并将权重添加到另一个布局...

    我在xml中有LinearLayout: android:id="@+id/progress" android:layout_width="fill_parent&quo ...

  5. android布局新建联系人,Android中设置搜素联系人的布局

    我们现在要达到下面的效果: 我们这样做了:我们可以先定义一个线性布局: 在线性布局中加入一个ImageView和一个Edittext 最后给这个线性布局加入背景,该背景就是外面的一个灰色边框. 我们来 ...

  6. android 布局加圆角,Android通用圆角布局

    名称 rclayout 语言 Android 平台 GitHub 作者 GcsSloop 该布局是一个可以任意设定布局圆角的大小,宽度,颜色等.可满足基于的开发工作中遇到的圆角布局需求. 效果图 效果 ...

  7. android 布局分析,关于Android应用程序界面五大布局的图文分析教程

    对于安卓系统应用开发中界面的布局有五大类,分别是LinearLayout(线性布局).FrameLayout(单帧布局).AbsoluteLayout(绝对布局).TablelLayout(表格布局) ...

  8. android 布局占一半,Android布局:width为父级的一半

    我有一个非常简单的布局,我不能让它看起来像我想要的.它是一个带有按钮和开关的LinearLayout.我希望他们显示一个在另一个之上,但我想要他们的宽度是父布局的一半. |--LinearLayout ...

  9. Android布局文件错误,android 布局文件常见错误

    1.'Missing contentDescription attribute on image' in XML 原因:缺少图片描述,在 ADT 16 开始会抛出这个警告,确保开发者为图片添加内容描述 ...

  10. android 布局的概念,Android布局

    Android 布局是应用界面开发的重要一环,在Android中,共有五种布局方式,分别是:LinearLayout(线性布局),FrameLayout(单帧布局),AbsoluteLayout(绝对 ...

最新文章

  1. oracle设置表字段小写,将oracle中的字段和表名全部修改为小写
  2. 【WEB安全】Xstream最新反序列化poc执行报错问题
  3. shell脚本游戏之:剪刀石头布
  4. “使命召唤”的新“吃鸡”模式味道如何?
  5. 8086CPU汇编寻址写法
  6. 淘宝商品数据库设计的一些经验
  7. ArrayList的remove方法(重写equals方法) 与LinkedList的常用操作
  8. [SimplePlayer] 2. 在屏幕上显示视频图像
  9. 触摸传感器的电路图符号_如何看懂汽车电路常用图形符号,看完这篇文章就懂了...
  10. java方法重载和重载方法_Java中的方法重载
  11. Linux入门(兄弟连)
  12. Glide图片框架使用详细介绍(一),手握5家大厂offer
  13. python里打印空格_python打印空格
  14. 中学生应该养成的良好习惯
  15. 华为手机备忘录怎样设置每个月12号短信提醒要做的事
  16. Mac OS X平台下QuickLook开发教程
  17. 微信小程序 | 小程序WXSS-WXML-WXS
  18. 怎么用几何画板制作图形平移和旋转
  19. mysql连接耗尽_避免数据库连接被耗尽的三种配置
  20. echarts label点击_echarts 点击方法总结,点任意一点获取点击数据,举例说明:在多图联动中点击绘制标线...

热门文章

  1. Godaddy域名push教程(域名转出教程)
  2. 扫呗扫码点餐,如何在扫呗后台给这个商户配一下支付授权地址
  3. php 499,服务频繁499(Nginx+PHP-fpm),应该从哪些角度入手追查这问题?
  4. nginx499问题
  5. linux md5加密文件,linux md5 加密字符串和文件方法
  6. Could not resolve dependencies for project com.koolearn:koo-b2b-tesa-api:jar:1.0-dev-SNAPSHOT
  7. 计算机应用基础实训教程侯冬梅,计算机应用基础实训教程
  8. 集合查询和查询结果处理
  9. Invalid bound statement (not found): com.lyf.eduservice.mapper.EduCourseMapper.getpublishInfo
  10. 双料大奖 | 奇点云获评「年度数字化创新最佳实践奖」「年度数字化服务最值得信赖品牌奖」