MotionEvent事件初探

我们对屏幕的点击,滑动,抬起等一系的动作都是由一个一个MotionEvent对象组成的。根据不同动作,主要有以下三种事件类型:
1.ACTION_DOWN:手指刚接触屏幕,按下去的那一瞬间产生该事件
2.ACTION_MOVE:手指在屏幕上移动时候产生该事件
3.ACTION_UP:手指从屏幕上松开的瞬间产生该事件

从ACTION_DOWN开始到ACTION_UP结束我们称为一个事件序列

正常情况下,无论你手指在屏幕上有多么骚的操作,最终呈现在MotionEvent上来讲无外乎下面两种。
1.点击后抬起,也就是单击操作:ACTION_DOWN -> ACTION_UP
2.点击后再风骚的滑动一段距离,再抬起:ACTION_DOWN -> ACTION_MOVE -> ... -> ACTION_MOVE -> ACTION_UP

举个栗子:

1.xml布局控件结构:

2.自定义控件MyTextView继承TextView

public class MyTextView extends TextView {private String tag = "MyTextView";public MyTextView(Context context) {super(context);}public MyTextView(Context context, AttributeSet attrs) {super(context, attrs);}public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {return super.dispatchTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {String aa = null;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:aa = "ACTION_DOWN";break;case MotionEvent.ACTION_MOVE:aa = "ACTION_MOVE";break;case MotionEvent.ACTION_UP:aa = "ACTION_UP";break;}Log.e(tag, "MyTextView---onTouchEvent---MotionEvent:" + aa);return super.onTouchEvent(event);}
}

3.自定义控件MyLinearLayoutA和MyLinearLayoutB继承LinearLayout

public class MyLinearLayoutA extends LinearLayout {private String tag = "MyLinearLayoutA";public MyLinearLayoutA(Context context) {super(context);}public MyLinearLayoutA(Context context, AttributeSet attrs) {super(context, attrs);}public MyLinearLayoutA(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return super.onInterceptTouchEvent(ev);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {return super.dispatchTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {String aa = null;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:aa = "ACTION_DOWN";break;case MotionEvent.ACTION_MOVE:aa = "ACTION_MOVE";break;case MotionEvent.ACTION_UP:aa = "ACTION_UP";break;}Log.e(tag, "MyLinearLayoutA---onTouchEvent---MotionEvent:" + aa);return super.onTouchEvent(event);}
}

4.MainActivity

public class MainActivity extends Activity {private String tag = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {MyLinearLayoutA lla = findViewById(R.id.lla);MyLinearLayoutB llb = findViewById(R.id.llb);MyTextView bb1 = findViewById(R.id.b1);lla.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {String aa = null;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:aa = "ACTION_DOWN";break;case MotionEvent.ACTION_MOVE:aa = "ACTION_MOVE";break;case MotionEvent.ACTION_UP:aa = "ACTION_UP";break;}Log.e(tag, "MyLinearLayoutA--setOnTouchListener---" + aa);return false;}});lla.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.e(tag, "MyLinearLayoutA-setOnClickListener");}});llb.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {String aa = null;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:aa = "ACTION_DOWN";break;case MotionEvent.ACTION_MOVE:aa = "ACTION_MOVE";break;case MotionEvent.ACTION_UP:aa = "ACTION_UP";break;}Log.e(tag, "MyLinearLayoutB--setOnTouchListener---" + aa);return false;}});llb.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.e(tag, "MyLinearLayoutB-setOnClickListener");}});bb1.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {String aa = null;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:aa = "ACTION_DOWN";break;case MotionEvent.ACTION_MOVE:aa = "ACTION_MOVE";break;case MotionEvent.ACTION_UP:aa = "ACTION_UP";break;}Log.e(tag, "MyTextView--setOnTouchListener---" + aa);return false;}});bb1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.e(tag, "MyTextView-setOnClickListener");}});}
}

总结下代码:

1.xml布局文件,1个LinearLayout下包含1个自定义MyLinearLayoutA(lla);MyLinearLayoutA(lla)下包含2个自定义MyTextView(a1、a2)和1个自定义MyLinearLayoutB(llb);MyLinearLayoutB(llb)下包含2个自定义MyTextView(b1、b2)。

2.自定义MyTextView继承TextView,重写dispatchTouchEvent()、和onTouchEvent();

3.自定义MyLinearLayoutA、MyLinearLayoutB继承LinearLayout,重写dispatchTouchEvent()、onTouchEvent()和onInterceptTouchEvent()(这个方法只有ViewGroup有,View没有);

4.在MainActivity里初始化MyLinearLayoutA(lla)、MyLinearLayoutB(llb)和MyTextView(a1),设置这三个控件的onTouchEventListener和onClickListener监听;

当我们单击MyTextView(b1)时:

07-25 16:01:47.161 3895-3895/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_DOWN
07-25 16:01:47.161 3895-3895/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_DOWN---isTrue:true
07-25 16:01:47.259 3895-3895/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_UP
07-25 16:01:47.259 3895-3895/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_UP---isTrue:true
07-25 16:01:47.259 3895-3895/com.mytest E/MainActivity: MyTextView-setOnClickListener

当我们在MyTextView(b1)上滑动时:

07-25 16:02:25.454 3895-3895/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_DOWN
07-25 16:02:25.455 3895-3895/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_DOWN
07-25 16:02:25.596 3895-3895/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_MOVE
07-25 16:02:25.596 3895-3895/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_MOVE
07-25 16:02:25.612 3895-3895/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_MOVE
07-25 16:02:25.612 3895-3895/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_MOVE
07-25 16:02:25.617 3895-3895/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_MOVE
07-25 16:02:25.618 3895-3895/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_MOVE
07-25 16:02:25.619 3895-3895/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_UP
07-25 16:02:25.619 3895-3895/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_UP
07-25 16:02:25.620 3895-3895/com.mytest E/MainActivity: MyTextView-setOnClickListener

细心的同学一定发现了我们常用的按钮的onclick事件都是在ACTION_UP以后才被调用的这和View的事件分发机制是不是有某种不可告人的关系呢?!

上面代码我们给TextView设置了OnTouchListener并重写了onTouch方法,方法返回值默认为false。如果这里我们返回true,那么你会发现onclick方法不执行了(log就不贴了)!!!What?
这些随着我们的深入探讨,结论就会浮出水面!针对MotionEvent,我们先说这么多。

MotionEvent事件分发

当一个MotionEvent产生了以后,就是你的手指在屏幕上做一系列动作的时候,系统需要把这一系列的MotionEvent分发给一个具体的View。我们重点需要了解这个分发的过程,那么系统是如何去判断这个事件要给哪个View,也就是说是如何进行分发的呢?

事件分发需要View的三个重要方法来共同完成

1.public boolean dispatchTouchEvent(MotionEvent event)
这个方法就负责事件的分发。如果一个MotionEvent传递给了View,那么dispatchTouchEvent方法一定会被调用!
返回值:表示是否消费了当前事件。可能是View本身的onTouchEvent方法消费,也可能是子View的dispatchTouchEvent方法中消费。返回true表示事件被消费,本次的事件终止。返回false表示View以及子View均没有消费事件,将调用父View的onTouchEvent方法

2.public boolean onInterceptTouchEvent(MotionEvent ev)
这个方法负责事件拦截,当一个ViewGroup在接到MotionEvent事件序列时候,首先会调用此方法判断是否需要拦截。特别注意,这是ViewGroup特有的方法,View并没有此拦截方法
返回值:是否拦截事件传递,返回true表示拦截了事件,那么事件将不再向下分发而是调用View本身的onTouchEvent方法。返回false表示不做拦截,事件将向下分发到子View的dispatchTouchEvent方法。

3.public boolean onTouchEvent(MotionEvent ev)
真正对MotionEvent进行处理或者说消费的方法。在dispatchTouchEvent里进行调用。
返回值:返回true表示事件被消费,本次的事件终止。返回false表示事件没有被消费,将调用父View的onTouchEvent方法

上面的三个方法可以用以下的伪代码来表示其之间的关系。

public boolean dispatchTouchEvent(MotionEvent ev) {boolean consume = false;//事件是否被消费if (onInterceptTouchEvent(ev)){//调用onInterceptTouchEvent判断是否拦截事件consume = onTouchEvent(ev);//如果拦截则调用自身的onTouchEvent方法}else{consume = child.dispatchTouchEvent(ev);//不拦截调用子View的dispatchTouchEvent方法}return consume;//返回值表示事件是否被消费,true事件终止,false调用父View的onTouchEvent方法}

下面简单说下ViewGroup和View在事件分发上的区别:

ViewGroup是View的子类,也就是说ViewGroup本身就是一个View,但是它可以包含子View(当然子View也可能是一个ViewGroup),所以不难理解,上面所展示的伪代码表示的是ViewGroup 处理事件分发的流程。而View本身是不存在分发,所以也没有拦截方法(onInterceptTouchEvent),它只能在onTouchEvent方法中进行处理消费或者不消费。

下面我们通过流程图梳理下事件分发机制:

可以看出事件的传递过程都是从父View到子View。这里有三点需要特别强调下:

1.子View可以通过requestDisallowInterceptTouchEvent方法干预父View的事件分发过程(ACTION_DOWN事件除外),而这就是我们处理滑动冲突常用的关键方法

2.对于View(注意!ViewGroup也是View)而言,如果设置了onTouchListener,那么OnTouchListener方法中的onTouch方法会被回调。onTouch方法返回true,则onTouchEvent方法不会被调用(onClick事件是在onTouchEvent中调用)所以三者优先级是onTouch->onTouchEvent->onClick

3.View 的onTouchEvent 方法默认都会消费掉事件(返回true),除非它是不可点击的(clickable和longClickable同时为false),View的longClickable默认为false,clickable需要区分情况,如Button的clickable默认为true,而TextView的clickable默认为false

下面通过文章开头举的例子继续改进来更深刻的理解

步骤1.ViewGroup中,事件拦截
通过修改自定义控件中onInterceptTouchEvent方法的返回值,返回true表示该控件拦截了该事件。修改MyLinearLayoutB中代码如下:

    @Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return true;}

运行代码,打印log:

07-25 16:05:47.862 4245-4245/com.mytest E/MainActivity: MyLinearLayoutB--setOnTouchListener---ACTION_DOWN
07-25 16:05:47.864 4245-4245/com.mytest E/MyLinearLayoutB: MyLinearLayoutB---onTouchEvent---MotionEvent:ACTION_DOWN
07-25 16:05:47.939 4245-4245/com.mytest E/MainActivity: MyLinearLayoutB--setOnTouchListener---ACTION_UP
07-25 16:05:47.939 4245-4245/com.mytest E/MyLinearLayoutB: MyLinearLayoutB---onTouchEvent---MotionEvent:ACTION_UP
07-25 16:05:47.950 4245-4245/com.mytest E/MainActivity: MyLinearLayoutB-setOnClickListener

结论:在LinearLayoutB中重写onInterceptTouchEvent方法,并把返回值改为true,此时LinearLayoutB确实拦截了此事件。

步骤2.在步骤1的基础上,事件消费

通过修改LinearLayoutB中onTouchEvent方法的返回值,返回值为true表示事件被消费,false表示事件不被消费,会向上层ViewGroup的onTouchEvent方法传递。

a.修改LinearLayoutB中onInterceptTouchEvent返回值为true,onTouchEvent返回值为true。

    @Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return true;}@Overridepublic boolean onTouchEvent(MotionEvent event) {String aa = null;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:aa = "ACTION_DOWN";break;case MotionEvent.ACTION_MOVE:aa = "ACTION_MOVE";break;case MotionEvent.ACTION_UP:aa = "ACTION_UP";break;}Log.e(tag, "MyLinearLayoutB---onTouchEvent---MotionEvent:" + aa);return true;}

打印Log为:

07-25 16:16:43.512 4614-4614/com.mytest E/MainActivity: MyLinearLayoutB--setOnTouchListener---ACTION_DOWN
07-25 16:16:43.514 4614-4614/com.mytest E/MyLinearLayoutB: MyLinearLayoutB---onTouchEvent---MotionEvent:ACTION_DOWN
07-25 16:16:43.571 4614-4614/com.mytest E/MainActivity: MyLinearLayoutB--setOnTouchListener---ACTION_UP
07-25 16:16:43.571 4614-4614/com.mytest E/MyLinearLayoutB: MyLinearLayoutB---onTouchEvent---MotionEvent:ACTION_UP
07-25 16:16:43.598 4614-4614/com.mytest E/MainActivity: MyLinearLayoutB-setOnClickListener

结论:onInterceptTouchEvent返回值为true,拦截了该事件;onTouchEvent返回值为true,消费了该事件。

b.修改onInterceptTouchEvent返回值为true,onTouchEvent返回值为false。

    @Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {return true;}@Overridepublic boolean onTouchEvent(MotionEvent event) {String aa = null;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:aa = "ACTION_DOWN";break;case MotionEvent.ACTION_MOVE:aa = "ACTION_MOVE";break;case MotionEvent.ACTION_UP:aa = "ACTION_UP";break;}Log.e(tag, "MyLinearLayoutB---onTouchEvent---MotionEvent:" + aa);return false;}

打印Log为:

07-25 16:19:11.675 4937-4937/com.mytest E/MainActivity: MyLinearLayoutB--setOnTouchListener---ACTION_DOWN
07-25 16:19:11.677 4937-4937/com.mytest E/MyLinearLayoutB: MyLinearLayoutB---onTouchEvent---MotionEvent:ACTION_DOWN
07-25 16:19:11.677 4937-4937/com.mytest E/MainActivity: MyLinearLayoutA--setOnTouchListener---ACTION_DOWN
07-25 16:19:11.679 4937-4937/com.mytest E/MyLinearLayoutA: MyLinearLayoutA---onTouchEvent---MotionEvent:ACTION_DOWN
07-25 16:19:11.766 4937-4937/com.mytest E/MainActivity: MyLinearLayoutA--setOnTouchListener---ACTION_UP
07-25 16:19:11.766 4937-4937/com.mytest E/MyLinearLayoutA: MyLinearLayoutA---onTouchEvent---MotionEvent:ACTION_UP
07-25 16:19:11.775 4937-4937/com.mytest E/MainActivity: MyLinearLayoutA-setOnClickListener

结论:onInterceptTouchEvent返回值为true,拦截了该事件;onTouchEvent返回值为false,该事件没有被消费,被传到了上传父ViewGroup(LinearLayoutA)的onTouchEvent方法中。

步骤3.我们再看下子View的事件处理。

ViewGroup的onInterceptTouchEvent返回值为false,事件被传给ViewGroup的子View(MYTextView),因为View没有自己的拦截方法onInterceptTouchEvent,所以View会直接调用自己的onTouchEvent方法;onTouchEvent返回值为true表示该事件被消费,false表示事件不被消费,继续向上传View的onTouchEvent传递。

a.LinearLayoutB(llb)的onInterceptTouchEvent返回值为false,MyTextView(b1)的onTouchEvent返回值为true.

代码比较简单就不贴了,直接看Log:

07-25 16:32:23.974 5306-5306/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_DOWN
07-25 16:32:23.976 5306-5306/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_DOWN
07-25 16:32:24.091 5306-5306/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_UP
07-25 16:32:24.091 5306-5306/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_UP
07-25 16:32:24.102 5306-5306/com.mytest E/MainActivity: MyTextView-setOnClickListener

结论:可以看出,View没有onInterceptTouchEvent方法拦截事件,通过设置onTouchEvent返回值为true,可以消费事件。

b.LinearLayoutB(llb)的onInterceptTouchEvent返回值为false,MyTextView(b1)的onTouchEvent返回值为false.

07-25 16:34:58.415 5623-5623/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_DOWN
07-25 16:34:58.416 5623-5623/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_DOWN
07-25 16:34:58.416 5623-5623/com.mytest E/MainActivity: MyLinearLayoutB--setOnTouchListener---ACTION_DOWN
07-25 16:34:58.417 5623-5623/com.mytest E/MyLinearLayoutB: MyLinearLayoutB---onTouchEvent---MotionEvent:ACTION_DOWN
07-25 16:34:58.536 5623-5623/com.mytest E/MainActivity: MyLinearLayoutB--setOnTouchListener---ACTION_UP
07-25 16:34:58.536 5623-5623/com.mytest E/MyLinearLayoutB: MyLinearLayoutB---onTouchEvent---MotionEvent:ACTION_UP
07-25 16:34:58.542 5623-5623/com.mytest E/MainActivity: MyLinearLayoutB-setOnClickListener

结论:MyTextView(b1)的onTouchEvent返回值为false,MyTextView没有消费该事件,该事件被传递到上层的LinearLayoutB(llb)的onTouchEvent方法中。

3.在步骤3-b的基础上(即LinearLayoutB(llb)的onInterceptTouchEvent返回值为false,MyTextView(b1)的onTouchEvent返回值为false),此时如果LinearLayoutB(llb)的onTouchEvent也为false。

Log:

07-25 16:41:39.172 6211-6211/com.mytest E/MainActivity: MyTextView--setOnTouchListener---ACTION_DOWN
07-25 16:41:39.172 6211-6211/com.mytest E/MyTextView: MyTextView---onTouchEvent---MotionEvent:ACTION_DOWN---isTrue:true
07-25 16:41:39.172 6211-6211/com.mytest E/MainActivity: MyLinearLayoutB--setOnTouchListener---ACTION_DOWN
07-25 16:41:39.173 6211-6211/com.mytest E/MyLinearLayoutB: MyLinearLayoutB---onTouchEvent---MotionEvent:ACTION_DOWN---isTrue:true
07-25 16:41:39.173 6211-6211/com.mytest E/MainActivity: MyLinearLayoutA--setOnTouchListener---ACTION_DOWN
07-25 16:41:39.173 6211-6211/com.mytest E/MyLinearLayoutA: MyLinearLayoutA---onTouchEvent---MotionEvent:ACTION_DOWN---isTrue:true
07-25 16:41:39.282 6211-6211/com.mytest E/MainActivity: MyLinearLayoutA--setOnTouchListener---ACTION_UP
07-25 16:41:39.285 6211-6211/com.mytest E/MyLinearLayoutA: MyLinearLayoutA---onTouchEvent---MotionEvent:ACTION_UP---isTrue:true
07-25 16:41:39.294 6211-6211/com.mytest E/MainActivity: MyLinearLayoutA-setOnClickListener

结论:此时,事件由LinearLayoutB继续向上传递,传递给父View(LinearLayoutA).

下一篇:Android View事件分发机制之源码解析。

Android View事件分发机制相关推荐

  1. Android View 事件分发机制详解

    想必很多android开发者都遇到过手势冲突的情况,我们一般都是通过内部拦截和外部拦截法解决此类问题.要想搞明白原理就必须了解View的分发机制.在此之前我们先来了解一下以下三个非常重要的方法: di ...

  2. 一文读懂Android View事件分发机制

    Android View 虽然不是四大组件,但其并不比四大组件的地位低.而View的核心知识点事件分发机制则是不少刚入门同学的拦路虎.ScrollView嵌套RecyclerView(或者ListVi ...

  3. 【Android View事件分发机制】关于拦截事件的注意点

    在父容器拦截事件时,为什么不能拦截DOWN事件呢? 先看看源码: 回顾一下事件分发机制原理,当事件来了之后,如果父容器不拦截,则会询问其child view ,当某child view 有事件需求,父 ...

  4. 【Android View事件分发机制】滑动冲突

    View内容滑动概念 scrollTo scrollBy scrollTo(x,y) x,y 是绝对值,如果x,y不变,重复调用是不会移动的. scrollBy(x,y) x,y是增量之,每次调用都会 ...

  5. 【Android View事件分发机制】原理

    事件体系中的几个基础类 MotionEvent 点击事件的封装. getX/Y 相当于当前View左上角的x,y坐标 getRawX/Y 相对于手机屏幕左上角的x,y坐标 GestureDetecto ...

  6. Android之事件分发机制

    本文主要包括以下内容 view的事件分发 viewGroup的事件分发 首先来看两张图 在执行touch事件时 首先执行dispatchTouchEvent方法,执行事件分发. 再执行onInterc ...

  7. Android面试老生常谈的 View 事件分发机制,看这一篇就够了

    本文首发我的微信公众号:徐公,想成为一名优秀的 Android 开发者,需要一份完备的 知识体系,在这里,让我们一起成长,变得更好~. 在 Android 开发当中,View 的事件分发机制是一块很重 ...

  8. android 点击事件消费,Android View事件分发和消费源码简单理解

    Android View事件分发和消费源码简单理解 前言: 开发过程中觉得View事件这块是特别烧脑的,看了好久,才自认为看明白.中间上网查了下singwhatiwanna粉丝的读书笔记,有种茅塞顿开 ...

  9. Android 系统(218)---Android的事件分发机制以及滑动冲突的解决

    Android的事件分发机制以及滑动冲突的解决 声明:  本文主要涉及VIew的事件分发与滑动冲突的解决,关于View的事件分发流程的部分内容参考自:  Android事件分发机制详解:史上最全面.最 ...

  10. Android系统(120)-android的事件分发机制

    android的事件分发机制 android的事件分发机制 比如说,现在你所在的公司中有一项任务被派发下来了,项目经理把项目交给你的老大,你的老大老大手下有很多人,看了看觉得你做很合适,把这个任务交给 ...

最新文章

  1. Xilinx IP解析之FIFO Generator v13.2
  2. JAVA基础学习大全(笔记)
  3. 彩色手绘元宵节插画风素材图片
  4. dede image.class.php,DEDE模板下载织梦DEDE 核心类TypeLink.class.php功能剖析
  5. tomcat日志中出现乱码
  6. javascript 学习总结(五)Function对象
  7. 深入理解计算机操作系统(六)
  8. 微信小程序模版合集下载,160个微信小程序源码.zip + 35个行业-微信小程序源码.zip
  9. html实现点击直接下载文件-前端教程
  10. Houdini分布式解算渲染,HQueue配置。
  11. Flexbox 完整指南
  12. Hadoop、Pig、Hive、Storm、NOSQL 学习资源收集【Updating】
  13. 斯坦福大学新课CS224W-2019-图网络机器学习算法-视频及ppt资源分享
  14. 这几款软件,你千万别装
  15. 8月11日 集训测试
  16. iphone4 美版电信烧号6.1.3电话号码括号问题解决办法
  17. CXF 框架webservice 概括与特点
  18. 【区块链与密码学】第6-7讲:SM9数字签名算法
  19. OCR图片相似度对比和分类算法
  20. 和平精英绝地求生服务器维护,手游和平精英辅助绝地求生今天维护什么时候结束?今天几点可以...

热门文章

  1. 毕设论文word转pdf(错误!未定义书签。 已解决)
  2. onlyoffice 回调传参数_onlyoffice服务在线编辑文档保存解析
  3. 新手入门教程:关于网站建设的主要流程和步骤
  4. php 求幂数,C 笔记九 求幂函数
  5. 浅析高速公路网络数据集制作
  6. 高速公路自动驾驶测试场景库
  7. sql修改服务器标记,KB974006-SQL Server 查询优化程序修复程序模型4199服务模型
  8. 混合基金量化投资策略应该怎么制定?
  9. 使用和风天气接口获取天气信息
  10. 一些心理学需要知道的点。