概述

Android中View框架的工作机制中,主要有三个过程:

1、View树的測量(measure)Android View框架的measure机制

2、View树的布局(layout) Android View框架的layout机制

3、View树的绘制(draw)Android View框架的draw机制

View框架的工作流程为:測量每一个View大小(measure)-->把每一个View放置到对应的位置(layout)-->绘制每一个View(draw)。

         本文主要讲述三大流程中的measure过程。

带着问题来思考整个measure过程。

1、系统为什么要有measure过程?

开发者在绘制UI的时候,基本都是通过XML布局文件的方式来配置UI,而每一个View必需要设置的两个群属性就是layout_width和layout_height,这两个属性代表着当前View的尺寸。

官方文档截图:

所以这两个属性的值是必需要指定的,这两个属性的取值仅仅能为三种类型:

                 1、固定的大小。比方100dp。

                 2、刚好包裹当中的内容,wrap_content。

                 3、想要和父布局一样大,match_parent / fill_parent。

因为Android希望提供一个更优雅的GUI框架,所以提供了自适应的尺寸,也就是 wrap_content 和 match_parent 。

试想一下,那假设这些属性仅仅同意设置固定的大小,那么每一个View的尺寸在绘制的时候就已经确定了。所以可能都不须要measure过程。可是因为须要满足自适应尺寸的机制,所以须要一个measure过程。

2、measure过程都干了点什么事?

因为上面提到的自适应尺寸的机制。所以在用自适应尺寸来定义View大小的时候。View的真实尺寸还不能确定。可是View尺寸终于须要映射到屏幕上的像素大小,所以measure过程就是干这件事。把各种尺寸值,经过计算。得到详细的像素值。measure过程会遍历整棵View树,然后依次測量每一个View真实的尺寸。详细是每一个ViewGroup会向它内部的每一个子View发送measure命令,然后由详细子View的onMeasure()来測量自己的尺寸。

最后測量的结果保存在View的mMeasuredWidth和mMeasuredHeight中。保存的数据单位是像素。

3、对于自适应的尺寸机制,怎样合理的測量一颗View树?

系统在遍历完布局文件后,针对布局文件,在内存中生成相应的View树结构,这个时候,整棵View树种的全部View对象,都还没有详细的尺寸,由于measure过程终于是要确定每一个View打的准确尺寸。也就是准确的像素值。

可是刚開始的时候。View中layout_width和layout_height两个属性的值,都仅仅是自适应的尺寸,也就是match_parent和wrap_content,这两个值在系统中为负数。所以系统不会把它们当成详细的尺寸值。所以当一个View须要把它内部的match_parent或者wrap_content转换成详细的像素值的时候。他须要知道两个信息。

        1、针对于match_parent,父布局当前详细像素值是多少,由于match_parent就是子View想要和父布局一样大。

        2、针对wrap_content,子View须要依据当前自己内部的content,算出一个合理的能包裹全部内容的最小值。可是假设这个最小值比当前父布局还大,那不行,父布局会告诉你,我仅仅有这么大,你也不应该超过这个尺寸。

因为树这样的数据结构的特殊性,我们在研究measure的过程时,能够仅仅研究一个ViewGroup和2个View的简单场景。大概示意图例如以下:

也就是说,在measure过程中,ViewGroup会依据自己当前的状况。结合子View的尺寸数据,进行一个综合评定,然后把相关信息告诉子View。然后子View在onMeasure自己的时候,一边须要考虑到自己的content大小,一边还要考虑的父布局的限制信息。然后综合评定,測量出一个最优的结果。

4、那么ViewGroup是怎样向子View传递限制信息的?

谈到传递限制信息。那就是MeasureSpec类了。该类贯穿于整个measure过程。用来传递父布局对子View尺寸測量的约束信息。简单来说,该类就保存两类数据。

                1、子View当前所在父布局的详细尺寸。

                2、父布局对子View的限制类型。

        那么限制类型又分为三种类型:

1、UNSPECIFIED,不限定。

意思就是,子View想要多大,我就能够给你多大,你放心大胆的measure吧,不用管其它的。也不用管我传递给你的尺寸值。(事实上Android高版本号中推荐,仅仅要是这个模式。尺寸设置为0)

                2、EXACTLY,精确的。意思就是。依据我当前的状况,结合你指定的尺寸參数来考虑。你就应该是这个尺寸,详细大小在MeasureSpec的尺寸属性中。自己去查看吧,你也不要管你的content有多大了。就用这个尺寸吧。

                3、AT_MOST,最多的。

意思就是,依据我当前的情况,结合你指定的尺寸參数来考虑,在不超过我给你限定的尺寸的前提下。你測量一个恰好能包裹你内容的尺寸就能够了。

源码分析

在View的源码中,提取到了以下一些关于measure过程的信息。

我们知道。整棵View树的根节点是DecorView,它是一个FrameLayout,所以它是一个ViewGroup。所以整棵View树的測量是从一个ViewGroup对象的measure方法開始的。

View:

1、measure

/** 開始測量一个View有多大,parent会在參数中提供约束信息。实际的測量工作是在onMeasure()中进行的,该方法会调用onMeasure()方法。所以仅仅有onMeasure能被也必需要被override */

public final void measure(int widthMeasureSpec, int heightMeasureSpec);

父布局会在自己的onMeasure方法中。调用child.measure ,这就把measure过程转移到了子View中。

2、onMeasure

/** 详细測量过程,測量view和它的内容。来决定測量的宽高(mMeasuredWidth  mMeasuredHeight )。

该方法中必需要调用setMeasuredDimension(int, int)来保存该view測量的宽高。 */

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec);

子View会在该方法中,依据父布局给出的限制信息,和自己的content大小,来合理的測量自己的尺寸。

3、setMeasuredDimension

/** 保存測量结果 */

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight);

当View測量结束后,把測量结果保存起来,详细保存在mMeasuredWidth和mMeasuredHeight中。

ViewGroup:

1、measureChildren

/** 让全部子view測量自己的尺寸。须要考虑当前ViewGroup的MeasureSpec和Padding。

跳过状态为gone的子view */

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec);-->getChildMeasureSpec()-->child.measure();

測量全部的子View尺寸,把measure过程交到子View内部。

2、measureChild

/** 測量单个View。须要考虑当前ViewGroup的MeasureSpec和Padding。 */

protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec);-->getChildMeasureSpec()-->child.measure();

对每个详细的子View进行測量。

3、measureChildWithMargins

/** 測量单个View,须要考虑当前ViewGroup的MeasureSpec和Padding、margins。 */

protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed);-->getChildMeasureSpec()-->child.measure();

对每个详细的子View进行測量。可是须要考虑到margin等信息。

4、getChildMeasureSpec

/** measureChildren过程中最困难的一部分,为child计算MeasureSpec。该方法为每一个child的每一个维度(宽、高)计算正确的MeasureSpec。目标就是把当前viewgroup的MeasureSpec和child的LayoutParams结合起来。生成最合理的结果。

比方,当前ViewGroup知道自己的准确大小。由于MeasureSpec的mode为EXACTLY,而child希望可以match_parent。这时就会为child生成一个mode为EXACTLY。大小为ViewGroup大小的MeasureSpec。

*/

public static int getChildMeasureSpec(int spec, int padding, int childDimension);

依据当前自身的状况。以及特定子View的尺寸參数,为特定子View计算一个合理的限制信息。

源码:

public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
int specMode = MeasureSpec.getMode(spec);
int specSize = MeasureSpec.getSize(spec); int size = Math.max(0, specSize - padding); int resultSize = 0;
int resultMode = 0; switch (specMode) {
// Parent has imposed an exact size on us
case MeasureSpec.EXACTLY:
if (childDimension >= 0) {
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size. So be it.
resultSize = size;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size. It can't be
// bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break; // Parent has imposed a maximum size on us
case MeasureSpec.AT_MOST:
if (childDimension >= 0) {
// Child wants a specific size... so be it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size, but our size is not fixed.
// Constrain child to not be bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size. It can't be
// bigger than us.
resultSize = size;
resultMode = MeasureSpec.AT_MOST;
}
break; // Parent asked to see how big we want to be
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
// Child wants a specific size... let him have it
resultSize = childDimension;
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size... find out how big it should
// be
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size.... find out how
// big it should be
resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
}
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}

伪代码:

    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
获取限制信息中的尺寸和模式。
switch (限制信息中的模式) {
case 当前容器的父容器。给当前容器设置了一个精确的尺寸:
if (子View申请固定的尺寸) {
你就用你自己申请的尺寸值即可了;
} else if (子View希望和父容器一样大) {
你就用父容器的尺寸值即可了;
} else if (子View希望包裹内容) {
你最大尺寸值为父容器的尺寸值。可是你还是要尽可能小的測量自己的尺寸。包裹你的内容就足够了;
}
break;
case 当前容器的父容器。给当前容器设置了一个最大尺寸:
if (子View申请固定的尺寸) {
你就用你自己申请的尺寸值即可了;
} else if (子View希望和父容器一样大) {
你最大尺寸值为父容器的尺寸值。可是你还是要尽可能小的測量自己的尺寸。包裹你的内容就足够了;
} else if (子View希望包裹内容) {
你最大尺寸值为父容器的尺寸值,可是你还是要尽可能小的測量自己的尺寸,包裹你的内容就足够了;
}
break;
case 当前容器的父容器,对当前容器的尺寸不限制:
if (子View申请固定的尺寸) {
你就用你自己申请的尺寸值即可了;
} else if (子View希望和父容器一样大) {
父容器对子View尺寸不做限制。
} else if (子View希望包裹内容) {
父容器对子View尺寸不做限制。
}
break;
} return 对子View尺寸的限制信息;
}

当自己定义View的时候,也须要处理measure过程。主要有两种情况。

1、继承自View的子类。

                须要覆写onMeasure来正确測量自己。最后都须要调用setMeasuredDimension来保存測量结果

一般来说。自己定义View的measure过程伪代码为:

int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec); int viewSize = 0; swith (mode) {
case MeasureSpec.EXACTLY:
viewSize = size; //当前View尺寸设置为父布局尺寸
break;
case MeasureSpec.AT_MOST:
viewSize = Math.min(size, getContentSize()); //当前View尺寸为内容尺寸和父布局尺寸其中的最小值
break;
case MeasureSpec.UNSPECIFIED:
viewSize = getContentSize(); //内容有多大。就设置尺寸为多大
break;
default:
break;
} setMeasuredDimension(viewSize);

2、继承自ViewGroup的子类。

                不但须要覆写onMeasure来正确測量自己。可能还要覆写一系列measureChild方法,来正确的測量子view。比方ScrollView。或者干脆放弃父类实现的measureChild规则,自己又一次实现一套測量子view的规则,比方RelativeLayout。最后都须要调用setMeasuredDimension来保存測量结果。

一般来说,自己定义ViewGroup的measure过程的伪代码为:

//ViewGroup開始測量自己的尺寸
viewGroup.onMeasure();
//ViewGroup为每一个child计算測量限制信息(MeasureSpec)
viewGroup.getChildMeasureSpec();
//把上一步生成的限制信息。传递给每一个子View,然后子View開始measure自己的尺寸
child.measure();
//子View測量完毕后,ViewGroup就能够获取每一个子View測量后的尺寸
child.getChildMeasuredSize();
//ViewGroup依据自己自身状况,比方Padding等,计算自己的尺寸
viewGroup.calculateSelfSize();
//ViewGroup保存自己的尺寸
viewGroupsetMeasuredDimension();

案例分析

非常多开发者都遇到过这样的需求,就是ScrollView内部嵌套ListView,而该ListView数据条数是不确定的。所以须要设置为包裹内容,然后就会发现ListView就会显示第一行出来。然后就会百度到一条解决方式,继承ListView。覆写onMeasure方法。

    @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}

问题是攻克了。可是非常多开发者并不知道为什么。

以下会从ScrollView和ListView的measure过程来分析一下。

1、为什么会出现上述问题?

备注:截取部分问题相关代码,并非完整代码。

看看ListView的onMeasure:

    @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final View child = obtainView(0, mIsScrap);
childHeight = child.getMeasuredHeight();
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = mListPadding.top + mListPadding.bottom + childHeight + getVerticalFadingEdgeLength() * 2;
if (heightMode == MeasureSpec.AT_MOST) {
// TODO: after first layout we should maybe start at the first visible position, not 0
heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
}
setMeasuredDimension(widthSize, heightSize);
mWidthMeasureSpec = widthMeasureSpec;
}
}

当MeasureSpec mode为UNSPECIFIED的时候,仅仅測量第一个item打的高度,跟问题描写叙述相符。所以我们推測可能是由于ScrollView传递了一个UNSPECIFIED限制给ListView。

再来看ScrollView的onMeasure代码:

    @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

调用了父类的onMeasure:

看看FrameLayout的onMeasure:

    @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (mMeasureAllChildren || child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
}
}
}

调用了measureChildWithMargins。可是由于ScrollView覆写了该方法,所以看看ScrollView的measureChildWithMargins方法:

    @Override
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {
final int childHeightMeasureSpec =
MeasureSpec.makeSafeMeasureSpec(MeasureSpec.getSize(parentHeightMeasureSpec),
MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

果然,它向ListView的onMeasure传递了一个UNSPECIFIED的限制。

为什么呢,想想,由于ScrollView。本来就是能够在竖直方向滚动的布局,所以。它对它全部的子View的高度就是UNSPECIFIED,意思就是,不限制子View有多高,由于我本来就是须要竖直滑动的,它的本意就是如此,所以它对子View高度不做不论什么限制。

2、为什么这样的解决方法能够解决问题?

看看ListView的onMeasure:

    @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final View child = obtainView(0, mIsScrap);
childHeight = child.getMeasuredHeight();
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = mListPadding.top + mListPadding.bottom + childHeight + getVerticalFadingEdgeLength() * 2;
if (heightMode == MeasureSpec.AT_MOST) {
// TODO: after first layout we should maybe start at the first visible position, not 0
heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
}
setMeasuredDimension(widthSize, heightSize);
mWidthMeasureSpec = widthMeasureSpec;
}
}

仅仅要让heightMode == MeasureSpec.AT_MOST,它就会測量它的完整高度,所以第一个数据,限制mode的值就确定下来了。

第二个数据就是尺寸上限,假设给个200。那么当ListView数据过多的时候。该ListView最大高度就是200了,还是不能全然显示内容,怎么办?那么就给个最大值吧,最大值是多少呢,Integer.MAX_VALUE?

先看一下MeasureSpec的代码说明:

        private static final int MODE_SHIFT = 30;
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
public static final int EXACTLY = 1 << MODE_SHIFT;
public static final int AT_MOST = 2 << MODE_SHIFT;

他用最高两位存储mode,用其它剩余未存储size。

所以Integer.MAX_VALUE >> 2,就是限制信息所能携带的最大尺寸数据。所以最后就须要用这两个值做成一个限制信息。传递给ListView的height维度。

也就是例如以下代码:

    @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}

自己动手

以下我们自己写一个自己定义的ViewGroup,让它内部的每个子View都垂直排布。而且让每个子View的左边界都距离上一个子View的左边界一定的距离。

而且支持wrap_content。大概看起来例如以下图所看到的:

实际执行效果例如以下图所看到的:

 代码例如以下:

public class VerticalOffsetLayout extends ViewGroup {

    private static final int OFFSET = 100;

    public VerticalOffsetLayout(Context context) {
super(context);
} public VerticalOffsetLayout(Context context, AttributeSet attrs) {
super(context, attrs);
} public VerticalOffsetLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width = 0;
int height = 0; int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
ViewGroup.LayoutParams lp = child.getLayoutParams();
int childWidthSpec = getChildMeasureSpec(widthMeasureSpec, 0, lp.width);
int childHeightSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp.height);
child.measure(childWidthSpec, childHeightSpec);
} switch (widthMode) {
case MeasureSpec.EXACTLY:
width = widthSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
int widthAddOffset = i * OFFSET + child.getMeasuredWidth();
width = Math.max(width, widthAddOffset);
}
break;
default:
break; } switch (heightMode) {
case MeasureSpec.EXACTLY:
height = heightSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
height = height + child.getMeasuredHeight();
}
break;
default:
break; } setMeasuredDimension(width, height);
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = 0;
int right = 0;
int top = 0;
int bottom = 0; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
left = i * OFFSET;
right = left + child.getMeasuredWidth();
bottom = top + child.getMeasuredHeight(); child.layout(left, top, right, bottom); top += child.getMeasuredHeight();
}
}
}

Android View框架的measure机制的更多相关文章

  1. Android View框架的draw机制

    概述 Android中View框架的工作机制中,主要有三个过程: 1.View树的测量(measure) Android View框架的measure机制 2.View树的布局(layout)Andr ...

  2. Android View框架的layout机制

    概述 Android中View框架的工作机制中,主要有三个过程: 1.View树的测量(measure) Android View框架的measure机制 2.View树的布局(layout)Andr ...

  3. Android View框架总结(八)ViewGroup事件分发机制

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52298780 上篇分析了View的事件分发流程,留了一个问题:如果上 ...

  4. Android View框架总结(四)View布局流程之Measure

    View树的measure流程 View的measures时序图 View布局流程之measure measure过程 View的measure过程 ViewGroup的measure过程 Frame ...

  5. Android View的事件分发机制探索

    概述 Android事件传递机制也是Android系统中比较重要的一块,事件类型有很多种,这里主要讨论TouchEvent的事件在framework层的传递处理机制.因为对于App开发人员来说,理解f ...

  6. Android View框架总结(七)View事件分发机制

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52282833 View布局告一段落,从本篇开始View事件相关分析, ...

  7. Android View框架总结(六)View布局流程之Draw过程

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52236145 View的Draw时序图 ViewRootImpl.p ...

  8. Android view 的事件分发机制

    1 事件的传递顺序是 Activity -> Window -> 顶层View touch 事件产生后,最先由 activity 的 dispatchTouchEvent 处理 /** * ...

  9. Android View框架总结(二)View焦点

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52263256 前言:View框架写到第六篇,发现前面第二篇竟然没有, ...

随机推荐

  1. amazeui学习笔记--css(布局相关1)--网格Grid

    amazeui学习笔记--css(布局相关1)--网格Grid 一.总结 基本使用 1.div+class布局:amaze里面采取的就是div+class的布局方式  <div class=&q ...

  2. Loadrunner--参数化知识点及参数池策略

    一.为何进行脚本参数化? 脚本在录制的时候,记录的参数都是常量值,这样,虚拟用户在执行同一个脚本,向服务器发送请求时,使用的都是同一个参数值,与实际不符.所以使用参数化技术. 二.参数化的逻辑? 对脚 ...

  3. 1、移动端 2、后台 3、 移动端,Web 端 4、 PC端

    移动端: 1.公众号:停开心 住总物业 2.app:  iso Android 停开心,住总停开心 后台:停开心智慧停车管理平台(所有的停车场) 移动端,Web端: 海投OA,公司OA PC端:收费软 ...

  4. x264代码剖析(十五):核心算法之宏块编码中的变换编码

    x264代码剖析(十五):核心算法之宏块编码中的变换编码 为了进一步节省图像的传输码率.须要对图像进行压缩,通常採用变换编码及量化来消除图像中的相关性以降低图像编码的动态范围.本文主要介绍变换编码的相 ...

  5. svg的世界、视窗、视野

    刚学svg时 看视频有人说了视窗和视野两个概念.学移动端时,又听说过视口这个概念.感觉还是有点绕的.以此博客来整理记录我查的资料. 1.世界 就是说svg的世界其实可以无限大,你想让它多大就多大,你可 ...

  6. ZOJ 2421 Recaman's Sequence

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1421 题目大意: 定义a^m为 a^m = a^(m-1) - m  如果a^ ...

  7. 微信端 h5 视频 video 自动播放

    document.addEventListener("WeixinJSBridgeReady",function(){ document.getElementById(" ...

  8. [Angular2 Form] patchValue, setValue and reset() for Form

    Learn how to update part of form model, full form model and reset whole form. We have form definetio ...

  9. thinkphp5 tp5 七牛云 上传图片

    七牛sdk地址https://files.cnblogs.com/files/zonglonglong/qiniu-php-sdk-7.2.2.rar 首先下载php的sdk将文件夹放到vendor ...

  10. jquery或js 获取url参数

    <script type="text/javascript"> function getUrlParam(name) { var reg = new RegExp(&q ...