Android 自定义ViewGroup
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews;/*** Example of writing a custom layout manager. This is a fairly full-featured* layout manager that is relatively general, handling all layout cases. You* can simplify it for more specific cases.*/
@RemoteViews.RemoteView
public class CustomLayout extends ViewGroup {/** The amount of space used by children in the left gutter. */private int mLeftWidth;/** The amount of space used by children in the right gutter. */private int mRightWidth;/** These are used for computing child frames based on their gravity. */private final Rect mTmpContainerRect = new Rect();private final Rect mTmpChildRect = new Rect();public CustomLayout(Context context) {super(context);}public CustomLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CustomLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}/*** Any layout manager that doesn't scroll will want this.*/@Overridepublic boolean shouldDelayChildPressedState() {return false;}/*** Ask all children to measure themselves and compute the measurement of this* layout based on the children.*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int count = getChildCount();// These keep track of the space we are using on the left and right for// views positioned there; we need member variables so we can also use// these for layout later.mLeftWidth = 0;mRightWidth = 0;// Measurement will ultimately be computing these values.int maxHeight = 0;int maxWidth = 0;int childState = 0;// Iterate through all children, measuring them and computing our dimensions// from their size.for (int i = 0; i < count; i++) {final View child = getChildAt(i);if (child.getVisibility() != GONE) {// Measure the child.measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);// Update our size information based on the layout params. Children// that asked to be positioned on the left or right go in those gutters.final LayoutParams lp = (LayoutParams) child.getLayoutParams();if (lp.position == LayoutParams.POSITION_LEFT) {mLeftWidth += Math.max(maxWidth,child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);} else if (lp.position == LayoutParams.POSITION_RIGHT) {mRightWidth += Math.max(maxWidth,child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);} else {maxWidth = Math.max(maxWidth,child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);}maxHeight = Math.max(maxHeight,child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);childState = combineMeasuredStates(childState, child.getMeasuredState());}}// Total width is the maximum width of all inner children plus the gutters.maxWidth += mLeftWidth + mRightWidth;// Check against our minimum height and widthmaxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());// Report our final dimensions.setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),resolveSizeAndState(maxHeight, heightMeasureSpec,childState << MEASURED_HEIGHT_STATE_SHIFT));}/*** Position all children within this layout.*/@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {final int count = getChildCount();// These are the far left and right edges in which we are performing layout.int leftPos = getPaddingLeft();int rightPos = right - left - getPaddingRight();// This is the middle region inside of the gutter.final int middleLeft = leftPos + mLeftWidth;final int middleRight = rightPos - mRightWidth;// These are the top and bottom edges in which we are performing layout.final int parentTop = getPaddingTop();final int parentBottom = bottom - top - getPaddingBottom();for (int i = 0; i < count; i++) {final View child = getChildAt(i);if (child.getVisibility() != GONE) {final LayoutParams lp = (LayoutParams) child.getLayoutParams();final int width = child.getMeasuredWidth();final int height = child.getMeasuredHeight();// Compute the frame in which we are placing this child.if (lp.position == LayoutParams.POSITION_LEFT) {mTmpContainerRect.left = leftPos + lp.leftMargin;mTmpContainerRect.right = leftPos + width + lp.rightMargin;leftPos = mTmpContainerRect.right;} else if (lp.position == LayoutParams.POSITION_RIGHT) {mTmpContainerRect.right = rightPos - lp.rightMargin;mTmpContainerRect.left = rightPos - width - lp.leftMargin;rightPos = mTmpContainerRect.left;} else {mTmpContainerRect.left = middleLeft + lp.leftMargin;mTmpContainerRect.right = middleRight - lp.rightMargin;}mTmpContainerRect.top = parentTop + lp.topMargin;mTmpContainerRect.bottom = parentBottom - lp.bottomMargin;// Use the child's gravity and size to determine its final// frame within its container.Gravity.apply(lp.gravity, width, height, mTmpContainerRect, mTmpChildRect);// Place the child.child.layout(mTmpChildRect.left, mTmpChildRect.top,mTmpChildRect.right, mTmpChildRect.bottom);}}}// ----------------------------------------------------------------------// The rest of the implementation is for custom per-child layout parameters.// If you do not need these (for example you are writing a layout manager// that does fixed positioning of its children), you can drop all of this.@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new CustomLayout.LayoutParams(getContext(), attrs);}@Overrideprotected LayoutParams generateDefaultLayoutParams() {return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);}@Overrideprotected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {return new LayoutParams(p);}@Overrideprotected boolean checkLayoutParams(ViewGroup.LayoutParams p) {return p instanceof LayoutParams;}/*** Custom per-child layout information.*/public static class LayoutParams extends MarginLayoutParams {/*** The gravity to apply with the View to which these layout parameters* are associated.*/public int gravity = Gravity.TOP | Gravity.START;public static int POSITION_MIDDLE = 0;public static int POSITION_LEFT = 1;public static int POSITION_RIGHT = 2;public int position = POSITION_MIDDLE;public LayoutParams(Context c, AttributeSet attrs) {super(c, attrs);// Pull the layout param values from the layout XML during// inflation. This is not needed if you don't care about// changing the layout behavior in XML.TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.CustomLayoutLP);gravity = a.getInt(R.styleable.CustomLayoutLP_android_layout_gravity, gravity);position = a.getInt(R.styleable.CustomLayoutLP_layout_position, position);a.recycle();}public LayoutParams(int width, int height) {super(width, height);}public LayoutParams(ViewGroup.LayoutParams source) {super(source);}}
}
先不说它的实现逻辑,看一下里面都用到了哪些方法(参数先忽略):onMeasure()、getChildCount()、getChildAt()、measureChildWithMargins()、setMeasuredDimension()、onLayout()、getPaddingLeft()、getMeasuredWidth()、layout()等。从这些方法可以看出,有些是View类里面的,有些是ViewGroup类里面的。因此不是说自定义ViewGroup时候使用的方法都是ViewGroup里面的,因为ViewGroup里面也包含了View,子View类在设置自己的位置、大小等时候需要调用自己的方法。所以下面的重点将从View以及ViewGroup常用方法两个方面来展开。
当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点。绘制过程从布局的根节点开始,从根节点开始测量和绘制整个layout tree。每一个ViewGroup 负责要求它的每一个孩子被绘制,每一个View负责绘制自己。因为整个树是按顺序遍历的,所以父节点会先被绘制,而兄弟节点会按照它们在树中出现的顺序被绘制。视图的布局分为两个过程:measure(测量)和layout(布局)。测量过程中,使用measure(int, int)方法,是一个自上而下的视图树的遍历。每个视图将尺寸规格在递归树。当这个测量过程结束时,每隔视图都存储了自己的大小。第二过程发生在layout(int,int,int,int),也是自顶向下。在这个过程中,每一个父容器通过使用在上一个过程中计算出来的数值来定位它的子视图。当一个视图的measure()方法返回时,其getMeasuredWidth()和getMeasuredHeight()值必须设置,以及这些视图的子节点。一个视图的measured width(宽度测量值)和measured height(高度测量值)必须尊重其父母容器的限制。这样可以保证在测量过程结束的时候,所有的父母都接受他们的孩子所有的测量。父容器可能不止一次使用measure()方法在子视图上面。比如,第一遍的时候,一个parent可能测量它的每一个孩子,并没有指定尺寸,parent只是为了发现它们想要多大;如果第一遍之后得知,所有孩子的无限制的尺寸总和太大或者太小,parent会再次对它的孩子调用measure()方法,这时候parent会设定规则,介入这个过程,使用实际的值。测量过程中使用两个类来和维度通信。 View.MeasureSpec类被子视图使用,用来通知他们的父类容器它们想要测量的大小以及位置。LayoutParams类用于描述一个视图的大小,LayoutParams是View用来告诉它的父容器它想要怎样被放置的参数。最基本的LayoutParams基类仅仅描述了View想要多大,即指明了尺寸属性。即View在XML布局时通常需要指明的宽度和高度属性。每一个维度都可以指定成下列三种值之一:
- 一个确切的数量
- MATCH_PARENT,这意味着要与其父一样大(减去填充)
- WRAP_CONTENT,这意味着认为希望是大到足以将其内容(加上填充)。
- UNSPECIFIED:这是父母用来确定所需的子视图的尺寸。例如,LinearLayout可能调用测量()在其孩子的高度不确定,宽度240找出给定的子视图要多高的宽度为240像素。
- EXACTLY:这是使用的父母对孩子施加一个精确的尺寸。孩子必须使用这个尺寸,保证所有的后代会适合这个尺寸。
- AT_MOST:这是使用的父母对孩子施加一个最大尺寸。孩子必须保证它和它的所有后代会适合这个尺寸。
- xml文件中的wrap_content-----MeasureSpec.AT_MOST:Child可以是自己任意的大小,但是有个绝对尺寸的上限。
- xml文件中的match_parent-----MeasureSpec.EXACTLY:Parent为child决定了一个绝对尺寸,child将会被赋予这些边界限制,不管child自己想要多大。
- xml文件中的-----MeasureSpec.UNSPECIFIED:这说明parent没有对child强加任何限制,child可以是它想要的任何尺寸。
在覆写onMeasure方法的时候,必须调用 setMeasuredDimension(int,int)来存储这个View经过测量得到的measured width and height。如果没有这么做,将会由measure(int, int)方法抛出一个IllegalStateException。覆写onMeasure方法的时候,子类有责任确保measured height and width至少为这个View的最小height和width。(getSuggestedMinimumHeight() and getSuggestedMinimumWidth())。典型的onMeasure的一个实现:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); //获取ViewGroup宽度 int height = MeasureSpec.getSize(heightMeasureSpec); //获取ViewGroup高度 setMeasuredDimension(width, height); //设置ViewGroup的宽高 int childCount = getChildCount(); //获得子View的个数,下面遍历这些子View设置宽高 for (int i = 0; i < childCount; i++) { View child = getChildAt(i); child.measure(viewWidth, viewHeight); //设置子View宽高 }
}
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { boolean optical = isLayoutModeOptical(this); if (optical != isLayoutModeOptical(mParent)) { Insets insets = getOpticalInsets(); int opticalWidth = insets.left + insets.right; int opticalHeight = insets.top + insets.bottom; measuredWidth += optical ? opticalWidth : -opticalWidth; measuredHeight += optical ? opticalHeight : -opticalHeight; } mMeasuredWidth = measuredWidth; //这就是保存到类变量mMeasuredHeight = measuredHeight; mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
// measure ourselves, this should set the measured dimension flag back onMeasure(widthMeasureSpec, heightMeasureSpec);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
/*** @see android.view.View#measure(int, int)*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));}/*** Determines the width of this view* @param measureSpec A measureSpec packed into an int* @return The width of the view, honoring constraints from measureSpec*/private int measureWidth(int measureSpec) {int result = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);if (specMode == MeasureSpec.EXACTLY) {// We were told how big to beresult = specSize;} else {// Measure the textresult = (int) mTextPaint.measureText(mText) + getPaddingLeft()+ getPaddingRight();if (specMode == MeasureSpec.AT_MOST) {// Respect AT_MOST value if that was what is called for by measureSpecresult = Math.min(result, specSize);}}return result;}/*** Determines the height of this view* @param measureSpec A measureSpec packed into an int* @return The height of the view, honoring constraints from measureSpec*/private int measureHeight(int measureSpec) {int result = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);mAscent = (int) mTextPaint.ascent();if (specMode == MeasureSpec.EXACTLY) {// We were told how big to beresult = specSize;} else {// Measure the text (beware: ascent is a negative number)result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()+ getPaddingBottom();if (specMode == MeasureSpec.AT_MOST) {// Respect AT_MOST value if that was what is called for by measureSpecresult = Math.min(result, specSize);}}return result;}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int mTotalHeight = 0; // 当然,也是遍历子View,每个都要告诉ViewGroup int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); // 获取在onMeasure中计算的视图尺寸 int measureHeight = childView.getMeasuredHeight(); int measuredWidth = childView.getMeasuredWidth(); childView.layout(left, mTotalHeight, measuredWidth, mTotalHeight + measureHeight); mTotalHeight += measureHeight; }
}
/*** {@inheritDoc}*/@Overrideprotected void dispatchDraw(Canvas canvas) {final int count = mChildrenCount;final View[] children = mChildren;int flags = mGroupFlags;if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;final boolean buildCache = !isHardwareAccelerated();for (int i = 0; i < count; i++) {final View child = children[i];if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {final LayoutParams params = child.getLayoutParams();attachLayoutAnimationParameters(child, params, i, count);bindLayoutAnimation(child);if (cache) {child.setDrawingCacheEnabled(true);if (buildCache) { child.buildDrawingCache(true);}}}}
4、drawChild(Canvas canvas, View child, long drawingTime))
5、getChildCount()
6、getChildAt()
7、onSizeChanged(int, int, int, int)
测量视图的大小,并保存起来
9、layout(int l, int t, int r, int b)
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {final int size = mChildrenCount;final View[] children = mChildren;for (int i = 0; i < size; ++i) {final View child = children[i];if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {measureChild(child, widthMeasureSpec, heightMeasureSpec);}}}
protected void measureChild(View child, int parentWidthMeasureSpec,int parentHeightMeasureSpec) {final LayoutParams lp = child.getLayoutParams();final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,mPaddingLeft + mPaddingRight, lp.width);final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,mPaddingTop + mPaddingBottom, lp.height);child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}
2、ViewGroup和View是一样的,不同的是ViewGroup中onLayout是一个必须被实现的抽象方法。同样的在layout()中调用onLayout(),在measure()中调用onMeasure()。
3、要实现自定义的ViewGroup,可以在其必须实现的onLayout()中调用子View的layout()。而子view的layout()又会去调用其onLayout()方法,那么这样就形成了所谓的“递归”布局过程了。
4、一个view的真正布局方法是setFrame(),这在layout()中有被调用到。即layout()中会先调用setFrame()设置组件的边界,再调用onLayout(),如果该view包含子view。则可以调用每个子view的layout()方法。
5、要指子view的大小可以在子view的onMeasure()中调用setMesauredDimension()来实现。
6、综上所述,android中组件绘制分为两个过程,测量(Measure)和布局(Layout)。测量过程通过measure()及onMeasure()方法实现,measure()方法中调用了onMeasure()方法,在onMeasure()中可以通过setMeasuredDimension()来设置组件的尺寸信息,这些尺寸信息在layout过程中会被使用到。布局过程是通过layout()及onLayout()方法实现的,layout()中调用了onLayout(),在layout()中可以使用getMeasuredHeight()或getMeasuredWidth()通过setFrame()来设置组件范围。所以在自定义的ViewGroup中往往只重写onLayout(),这是因为ViewGroup的layout()方法已经被系统调用了。
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
public class CustomViewGroup extends ViewGroup {
public CustomViewGroup(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public CustomViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public CustomViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
@Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
// TODO Auto-generated method stub
}
}
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Color;
import android.widget.ImageView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(mCustomViewGroup);
}
}
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- put first view to left. -->
<TextView
android:layout_width="50dp"
android:layout_height="100dp"
android:background="@drawable/ic_launcher"
android:text="l1" />
<!-- stack second view to left. -->
<TextView
android:layout_width="50dp"
android:layout_height="100dp"
android:background="@drawable/ic_launcher"
android:text="l2" />
</com.example.viewgroupdemo.CustomViewGroup>
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = MeasureSpec.getSize(widthMeasureSpec);Log.i("onMeasure--width", width + "");int height = MeasureSpec.getSize(heightMeasureSpec);Log.i("onMeasure--height", height + "");setMeasuredDimension(width, height);measureChildren(widthMeasureSpec, heightMeasureSpec); }
@Overrideprotected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {// TODO Auto-generated method stubfor (int i = 0; i < getChildCount(); i++) {View v=getChildAt(i);v.layout(arg1, arg2, arg3, arg4);}}
@Overrideprotected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {// 屏幕方向改变时候会调用Log.i("onLayout--arg0", arg0 + "");Log.i("onLayout--arg1", arg1 + "");Log.i("onLayout--arg2", arg2 + "");Log.i("onLayout--arg3", arg3 + "");Log.i("onLayout--arg4", arg4 + "");int childCount = getChildCount();Log.i("onLayout--childCount", childCount + "");for (int i = 0; i < childCount; i++) {View view = getChildAt(i);int chiledWidth = view.getMeasuredWidth();Log.i("onLayout--chiledWidth", chiledWidth + "");int chiledHeight = view.getMeasuredHeight();Log.i("onLayout--chiledHeight", chiledHeight + "");view.layout(arg1, arg2, chiledWidth, chiledHeight);}}
Android 自定义ViewGroup相关推荐
- android自定义viewgroup之我也玩瀑布流
先看效果图吧, 继上一篇<android自定义viewgroup实现等分格子布局>中实现的布局效果,这里稍微有些区别,每个格子的高度不规则,就是传说的瀑布流布局,一般实现这种效果,要么用第 ...
- android 自定义flowlayout,Android 自定义ViewGroup之实现FlowLayout-标签流容器
本篇文章讲的是Android 自定义ViewGroup之实现标签流式布局-FlowLayout,开发中我们会经常需要实现类似于热门标签等自动换行的流式布局的功能,网上也有很多这样的FlowLayout ...
- Android自定义文件路径箭头,Android自定义ViewGroup实现带箭头的圆角矩形菜单
本文和大家一起做一个带箭头的圆角矩形菜单,大概长下面这个样子: 要求顶上的箭头要对准菜单锚点,菜单项按压反色,菜单背景色和按压色可配置. 最简单的做法就是让UX给个三角形的图片往上一贴,但是转念一想这 ...
- Android自定义ViewGroup实现朋友圈九宫格控件
在我们的实际应用中,经常需要用到自定义控件,比如自定义圆形头像,自定义计步器等等,这篇文章主要给大家介绍了关于Android自定义ViewGroup实现朋友圈九宫格控件的相关资料,需要的朋友可以参考下 ...
- Android 自定义ViewGroup之实现FlowLayout-标签流容器
本篇文章讲的是Android 自定义ViewGroup之实现标签流式布局-FlowLayout,开发中我们会经常需要实现类似于热门标签等自动换行的流式布局的功能,网上也有很多这样的FlowLayout ...
- Android自定义ViewGroup基本步骤
1.自定义属性,获取自定义属性,可参考 Android自定义View基本步骤 2.onMeasure() 方法,for循环测量子View,根据子View的宽高来计算自己的宽 高 3.onDra ...
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu[转]
http://blog.csdn.net/jj120522/article/details/8095852 示意图就不展示了,和上一节的一样,滑动菜单SlidingMenu效果如何大家都比较熟悉,在这 ...
- 教你搞定Android自定义ViewGroup
ViewGroup 我们知道ViewGroup就是View的容器类,我们经常用的LinearLayout,RelativeLayout等都是ViewGroup的子类,因为ViewGroup有很多子Vi ...
- Android自定义ViewGroup的OnMeasure和onLayout详解
前一篇文章主要讲了自定义View为什么要重载onMeasure()方法http://blog.csdn.net/tuke_tuke/article/details/73302595 那么,自定义Vie ...
- android 自定义viewgroup onmeasure,一篇文章搞懂Android 自定义Viewgroup的难点
本文的目的 目的在于教会大家到底如何自定义viewgroup,自定义布局和自定义测量到底如何写.很多网上随便搜搜的概念和流程图这里不再过多描述了,建议大家看本文之前,先看看基本的自定义viewgrou ...
最新文章
- 这只机械手太硬核!失去手指的机械工程师独立打造,网友:赛博朋克,太酷了...
- Docker 私有仓库最简便的搭建方法
- HBase的列族式存储介绍
- malloc,free,new,delete解析(原)
- jupyter notebook 操作
- 两个数相乘积一定比每个因数都大_两个多位数相乘,积一定比每一个因数都大。[ ]...
- Python+matplotlib调用LaTex引擎渲染公式
- atitit.web 推送实现方案集合
- 超越QQ Mail文件中转站---大文件上传设计思路和实践 原创 王泽宾
- java概述及我的第一个java项目
- Emotron伊尔通软启动器维修MSF-5705252C-N-AU
- SpringBoot 使用freemarker 处理文档,找不到文件位置(报错:basePackagePath=““ /* relatively to resourceLoaderClass pkg)
- 机器学习基础(四)——决策树与随机森林
- 女生玩游戏什么款式蓝牙耳机好用?小清新高颜值游戏蓝牙耳机推荐
- vue-admin-template默认英文改成中文
- Multisim仿真 错误Error: Shorted voltage sources found: Vfgen_src_negative
- 戴愫-有效提升与陌生人的社交能力
- mysql list dbs 代替_mysql_list_dbs函数的用法实例汇总
- 北京冬奥村:让科技蕴含温度
- Python表情包处理教程:如何过滤和替换emoji表情?
热门文章
- xxx/labelKeypoint/utils/qt.py:81: RuntimeWarning: invalid value encountered in double_scalars
- MapReduce之Job工具类开发
- R读写Excel文件中数据的方法
- 实时搜索专家Krzana正式进军金融大数据市场
- ubuntu14安装tensorflow并测试
- Codeforces Round #275 (Div. 2) D
- CentOS 6.5 64位 安装zabbix-2.2.0
- Ubuntu 安装 JDK 7 / JDK8 的两种方式
- 理解 JMeter 聚合报告(Aggregate Report)
- eclipse的编辑器样式风格设置