详解Paint的setXfermode(Xfermode xfermode)
一、setXfermode(Xfermode xfermode)
Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的“过渡”其实就是图像混合的一种,这个方法跟我们上面讲到的setColorFilter蛮相似的。查看API文档发现其果然有三个子类:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode,这三个子类实现的功能要比setColorFilter的三个子类复杂得多。
二、AvoidXfermode
2.1 关闭硬件加速
这个API因为不支持硬件加速在API 16已经过时了(大家可以在HardwareAccel查看那些方法不支持硬件加速)如果想在高于API 16的机子上进行测试,必须现在应用或手机设置中关闭硬件加速,在应用中我们可以通过在AndroidManifest.xml文件中设置application节点下的android:hardwareAccelerated属性为false来关闭硬件加速:
<application
android:allowBackup="true"
android:hardwareAccelerated="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
注意:如果你在设置中开启了强制硬件加速(强制使用GPU进行绘制),在代码中配置也是没用的。
2.2 构造方法
AvoidXfermode只有一个含参的构造方法:AvoidXfermode(int opColor, int tolerance, AvoidXfermode.Mode mode)
AvoidXfermode有三个参数,第一个opColor表示一个16进制的可以带透明通道的颜色值例如0x12345678;第二个参数tolerance表示容差值,那么什么是容差呢?你可以理解为一个可以标识“精确”或“模糊”的东西,表示当前颜色和opColor的差异程度;最后一个参数表示AvoidXfermode的具体模式,其可选值只有两个:AvoidXfermode.Mode.AVOID或者AvoidXfermode.Mode.TARGET,两者的意思也非常简单,我们逐一来看。
2.3 AvoidXfermode.Mode.TARGET
在该模式下Android会判断画布上的颜色是否会有跟opColor不一样的颜色,opColor可以理解为基准色,仅仅用来做判断。比如我opColor是红色,那么在TARGET模式下就会去判断我们的画布上是否有存在红色(opColor)的地方,如果有,则把该区域“染”上一层我们”画笔的颜色“,否则不“染”色,而tolerance容差值则表示画布上的像素和我们定义的红色之间的差别是多少的时候才去“染”的,比如当前画布有一个像素的色值是(200, 20, 13),而我们的红色值为(255, 0, 0),当tolerance容差值为255时,即便(200, 20, 13)并不等于红色值也会被“染”色,容差值越大“染”色范围越广反之则反。
如果我们想要让图片中白色像素被染上紫色:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); // 先画一个图片
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.kale);
canvas.drawBitmap(bitmap, 240, 600, mPaint); /*
* 当画布中有跟0XFFFFFFFF色不一样的地方时候才“染”色
* 第一个参数颜色是基本色,绘制的时候会判断有没有和基本色相似的颜色(相似程度用容差值表示),有的话就用画笔当前的颜色去绘制那个像素点。
*/
AvoidXfermode avoidXfermode = new AvoidXfermode(0XFFFFFFFF, 255, AvoidXfermode.Mode.TARGET); // “染”什么色是由我们自己决定的
mPaint.setARGB(255, 211, 53, 243); // 设置模式
mPaint.setXfermode(avoidXfermode); // 在图片同等位置上,画一个和位图大小一样的矩形
canvas.drawRect(240, 600, 240 + bitmap.getWidth(), 600 + bitmap.getHeight(), mPaint);
}
得到下面的效果:
如果提高容差值,那么接近白色的区域也会被染上紫色。
注意:如果你没关闭硬件加速,那么就会得到像下图这样的一个色块。
2.4 AvoidXfermode.Mode.AVOID
则与TARGET恰恰相反,TARGET是我们指定的颜色是否与画布的颜色一样,而AVOID是我们指定的颜色是否与画布不一样,其他的都与TARGET类似
AvoidXfermode(0XFFFFFFFF, 0, AvoidXfermode.Mode.AVOID):
当模式为AVOID容差值为0时,只有当图片中像素颜色值与0XFFFFFFFF完全不一样的地方才会被染色
AvoidXfermode(0XFFFFFFFF, 255, AvoidXfermode.Mode.AVOID):
当容差值为255时,只要与0XFFFFFFFF稍微有点不一样的地方就会被染色
那么这玩意究竟有什么用呢?比如说当我们只想在白色的区域画点东西或者想把白色区域的地方替换为另一张图片的时候就可以采取这种方式!
三、PixelXorXfermode
与AvoidXfermode一样也在API 16过时了,该类也提供了一个含参的构造方法PixelXorXfermode(int opColor),该类的计算实现很简单,从官方给出的计算公式来看就是:op ^ src ^ dst,像素色值的按位异或运算,如果大家感兴趣,可以自己用一个纯色去尝试,并自己计算异或运算的值是否与得出的颜色值一样,这里我就不讲了,Because it was deprecated and useless。
四、PorterDuffXfermode
Xfermode的最后一个子类也是惟一一个没有过时且沿用至今的子类,这个类是否强大,值得我们好好的学习学习。该类同样有且只有一个含参的构造方法PorterDuffXfermode(PorterDuff.Mode mode),这个PorterDuff.Mode大家看后是否会有些面熟,它跟上面我们讲ColorFilter时候用到的PorterDuff.Mode是一样的!PorterDuffXfermode就是图形混合模式的意思。
4.1 多种混合效果
这张图片从一定程度上形象地说明了图形混合的作用,两个图形一圆一方通过一定的计算产生不同的组合效果,在API中Android为我们提供了18种(比上图多了两种ADD和OVERLAY)模式:
这18种模式Android还为我们提供了它们的计算方式比如LIGHTEN的计算方式为[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)]
Sa全称为Source alpha表示源图的Alpha通道;
Sc全称为Source color表示源图的颜色;
Da全称为Destination alpha表示目标图的Alpha通道;
Dc全称为Destination color表示目标图的颜色.
细心的朋友会发现“[……]”里分为两部分,其中“,”前的部分为“Sa + Da - Sa*Da”这一部分的值代表计算后的Alpha通道,而“,”后的部分为“Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)”这一部分的值代表计算后的颜色值,图形混合后的图片依靠这个矢量来计算ARGB的值,如果大家感兴趣可以查看维基百科中对Alpha合成的解释:http://en.wikipedia.org/wiki/Alpha_compositing。
当大家看到上面API DEMO给出的效果时一定会觉得PorterDuffXfermode其实就是简单的图形交并集计算,比如重叠的部分删掉或者叠加等等,事实上呢!PorterDuffXfermode的计算绝非是根据于此!
4.2 准备好做测试的图片和代码框架
我们将在不同的模式下混合这两个Bitmap来看看这两个渐变色的颜色值在不同的混合模式下究竟发生了什么?图片中的黑色部分是完全透明的。
先看看我们的测试代码:
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class PorterDuffView extends View {
/*
* PorterDuff模式常量
* 可以在此更改不同的模式测试
*/
private static final PorterDuff.Mode MODE = PorterDuff.Mode.ADD; private static final int RECT_SIZE_SMALL = 400;// 左右上方示例渐变正方形的尺寸大小
private static final int RECT_SIZE_BIG = 800;// 中间测试渐变正方形的尺寸大小 private Paint mPaint;// 画笔 private PorterDuffBO porterDuffBO;// PorterDuffView类的业务对象
private PorterDuffXfermode porterDuffXfermode;// 图形混合模式 private int screenW, screenH;// 屏幕尺寸
private int s_l, s_t;// 左上方正方形的原点坐标
private int d_l, d_t;// 右上方正方形的原点坐标
private int rectX, rectY;// 中间正方形的原点坐标 public PorterDuffView(Context context, AttributeSet attrs) {
super(context, attrs); // 实例化画笔并设置抗锯齿
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 实例化业务对象
porterDuffBO = new PorterDuffBO(); // 实例化混合模式
porterDuffXfermode = new PorterDuffXfermode(MODE); // 计算坐标
calu(context);
} /**
* 计算坐标
*
* @param context
* 上下文环境引用
*/
private void calu(Context context) {
// 获取包含屏幕尺寸的数组
int[] screenSize = MeasureUtil.getScreenSize((Activity) context); // 获取屏幕尺寸
screenW = screenSize[0];
screenH = screenSize[1]; // 计算左上方正方形原点坐标
s_l = 0;
s_t = 0; // 计算右上方正方形原点坐标
d_l = screenW - RECT_SIZE_SMALL;
d_t = 0; // 计算中间方正方形原点坐标
rectX = screenW / 2 - RECT_SIZE_BIG / 2;
rectY = RECT_SIZE_SMALL + (screenH - RECT_SIZE_SMALL) / 2 - RECT_SIZE_BIG / 2;
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 设置画布颜色为黑色以便我们更好地观察
canvas.drawColor(Color.BLACK); // 设置业务对象尺寸值计算生成左右上方的渐变方形
porterDuffBO.setSize(RECT_SIZE_SMALL); /*
* 画出左右上方两个正方形
* 其中左边的的为src右边的为dis
*/
canvas.drawBitmap(porterDuffBO.initSrcBitmap(), s_l, s_t, mPaint);
canvas.drawBitmap(porterDuffBO.initDisBitmap(), d_l, d_t, mPaint); /*
* 将绘制操作保存到新的图层(更官方的说法应该是离屏缓存)我们将在1/3中学习到Canvas的全部用法这里就先follow me
*/
int sc = canvas.saveLayer(0, 0, screenW, screenH, null, Canvas.ALL_SAVE_FLAG); // 重新设置业务对象尺寸值计算生成中间的渐变方形
porterDuffBO.setSize(RECT_SIZE_BIG); // 先绘制dis目标图
canvas.drawBitmap(porterDuffBO.initDisBitmap(), rectX, rectY, mPaint); // 设置混合模式
mPaint.setXfermode(porterDuffXfermode); // 再绘制src源图
canvas.drawBitmap(porterDuffBO.initSrcBitmap(), rectX, rectY, mPaint); // 还原混合模式
mPaint.setXfermode(null); // 还原画布
canvas.restoreToCount(sc);
}
}
代码中我们使用到了View的离屏缓冲,也通俗地称之为层,这个概念很简单,我们在绘图的时候新建一个“层”,所有的绘制操作都在该层上而不影响该层以外的图像,比如代码中我们在绘制了画布颜色和左右上方两个方形后就新建了一个图层来绘制中间的大正方形,这个方形和左右上方的方形是在两个不同的层上的。很类似PS中的层。
演示说明:我们上方会绘制两个图像,左边是原始图像,右边是目标图像,中间的大正方形是最终的结果。所有图片黑色部分都是透明的,之所以是黑色的,是因为背景是黑色的。
4.3 详解各种模式
PorterDuff.Mode.ADD
计算方式:Saturate(S + D);
说明:饱和相加
从计算方式和显示的结果我们可以看到,ADD模式简单来说就是对图像饱和度进行相加,这个模式在应用中不常用,我唯一一次使用它是通过代码控制RGB通道的融合生成图片。
PorterDuff.Mode.CLEAR
计算方式:[0, 0];
说明:清除
清除图像,很好理解。
PorterDuff.Mode.DARKEN
计算方式:[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)];
说明:变暗
这个模式计算方式目测很复杂,其实效果很好理解,两个图像混合,较深的颜色总是会覆盖较浅的颜色,如果两者深浅相同则混合。
如图,黄色覆盖了红色,蓝色和青色因为是跟透明混合所以不变。细心的朋友会发现青色和黄色之间有一层类似橙色的过渡色,这就是混合的结果。在实际的测试中源图和目标图的DARKEN混合偶尔会有相反的结果比如红色覆盖了黄色,这源于Android对颜色值“深浅”的定义,我暂时没有在官方查到有关资料不知道是否与图形图像学一致。DARKEN模式的应用在图像色彩方面比较广泛我们可以利用其特性来获得不同的成像效果,这点与之前介绍的ColorFilter有点类似。
PorterDuff.Mode.DST
计算方式:[Da, Dc];说明:只绘制目标图像
很好理解,就是不管原始的图片,之是绘制目标图像。这里的目标图像是右上方的图像,所以中间的结果区域和右上方的图像完全一致。
PorterDuff.Mode.DST_ATOP
计算方式:[Sa, Sa * Dc + Sc * (1 - Da)];
说明:在源图像和目标图像相交的地方绘制目标图像而在不相交的地方绘制源图像
因为黑色区域是透明区域,所以原图和目标图片不会有相交的地方,故最终的结果图片下半部分也是黑色的。原图上面是不透明,目标图片右边是不透明,所以相交之处是左上方。结果也显示,在不相交的地方仅仅绘制了原始图像。
PorterDuff.Mode.DST_IN
计算方式:[Sa * Da, Sa * Dc];
说明:只在源图像和目标图像相交的地方绘制目标图像
之前分析过了,原图和目标图片相交的地方只有左上区域,结果也显示在左上区域仅仅绘制了目标图像。我想最常见的应用就是蒙板绘制,利用源图作为蒙板“抠出”目标图上的图像。
例子:
我们把原图先画到手机屏幕上:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);// 先画一个图片
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.src);
canvas.drawBitmap(bitmap, 180, 200, null); }
我们想仅仅留下人物,取消上面的文字和白色背景该咋办呢?这就要用到了遮罩图片了。
用到的图片:
实现代码:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); // 原始图片
Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.src);
// 图片的遮罩
Bitmap mask = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.mask); /**
* 分析:
* 当前的模式是相交处绘制目标图像,那么我们的src就应该是目标图像了。mask是遮罩,反正是不会被绘制的,理解来看它应该做原始图像。
* 结论:
* 原始图像:mask
* 目标图像:src
*/ /*
* 将绘制操作保存到新的图层(更官方的说法应该是离屏缓存)
*/
int sc = canvas.saveLayer(0, 0, 720, 1080, null, Canvas.ALL_SAVE_FLAG); // 先绘制dis目标图
canvas.drawBitmap(src, 180, 200, mPaint); // 设置混合模式 (只在源图像和目标图像相交的地方绘制目标图像)
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); // 再绘制src源图
canvas.drawBitmap(mask, 180, 200, mPaint); // 还原混合模式
mPaint.setXfermode(null); // 还原画布
canvas.restoreToCount(sc);
}
最终结果:
PorterDuff.Mode.DST_OUT
说明:只在源图像和目标图像相交的地方绘制源图像
上面我们做了PorterDuff.Mode.DST_IN的例子,不妨也来做做PorterDuff.Mode.DST_OUT的例子吧。这个例子是用遮罩图片和来做的,目的是扣出剪影。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 图片的遮罩
Bitmap mask = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.mask); /*
* 将绘制操作保存到新的图层(更官方的说法应该是离屏缓存)
*/
int sc = canvas.saveLayer(0, 0, 720, 1080, null, Canvas.ALL_SAVE_FLAG); // 先绘制一层颜色
canvas.drawColor(0xFF8f66DA); // 设置混合模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); // 再绘制src源图
canvas.drawBitmap(mask, 180, 200, mPaint); // 还原混合模式
mPaint.setXfermode(null); // 还原画布
canvas.restoreToCount(sc); }
结果:
PorterDuff.Mode.DST_OVER
计算方式:[Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc];
说明:在源图像的上方绘制目标图像
就是把目标图像放在了原图上方,产生简单的叠加效果。
PorterDuff.Mode.LIGHTEN
计算方式:[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)];
说明:变亮
与DARKEN相反,把原图和目标图中的颜色进行比较,找到颜色较明亮的,区域进行绘制。比如,黄色比红色亮,所以绘制了黄色,没有绘制红色。
PorterDuff.Mode.MULTIPLY
计算方式:[Sa * Da, Sc * Dc];
说明:正片叠底
该模式通俗的计算方式很简单,源图像素颜色值乘以目标图像素颜色值除以255即得混合后图像像素的颜色值,该模式在设计领域应用广泛,因为其特性黑色与任何颜色混合都会得黑色,在手绘的上色、三维动画的UV贴图绘制都有应用,具体效果大家自己尝试我就不说了。
PorterDuff.Mode.OVERLAY
计算方式:未给出;
说明:叠加
这个模式没有在官方的API DEMO中给出,谷歌也没有给出其计算方式,在实际效果中其对亮色和暗色不起作用,也就是说对黑白色无效,它会将源色与目标色混合产生一种中间色,这种中间色生成的规律也很简单,如果源色比目标色暗,那么让目标色的颜色倍增,否则颜色递减。
PorterDuff.Mode.SCREEN
计算方式:[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc];
说明:滤色
滤色产生的效果我认为是Android提供的几个色彩混合模式中最好的,它可以让图像焦媃幻化,有一种色调均和的感觉。
用代码来看看效果:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); // 原始图片
Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.src); /*
* 将绘制操作保存到新的图层(更官方的说法应该是离屏缓存)
*/
int sc = canvas.saveLayer(0, 0, 720, 1080, null, Canvas.ALL_SAVE_FLAG); // 先绘制dis目标图
//canvas.drawBitmap(src, 180, 200, mPaint); // 先绘制一层带透明度的颜色
canvas.drawColor(0xcc1c093e); // 设置混合模式 (只在源图像和目标图像相交的地方绘制目标图像)
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN)); // 再绘制src源图
canvas.drawBitmap(src, 180, 200, mPaint); // 还原混合模式
mPaint.setXfermode(null); // 还原画布
canvas.restoreToCount(sc);
}
代码中的紫色是有透明度的,让它和原图进行混合,给原图添加了一点点的淡紫色。
PorterDuff.Mode.SRC
计算方式:[Sa, Sc];
说明:只显示源图
只绘制源图,SRC类的模式跟DIS正好相反。
PorterDuff.Mode.SRC_ATOP
计算方式:[Da, Sc * Da + (1 - Sa) * Dc];
说明:在源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像
原图和目标图相交的地方是左上角,所以左上角是原图,其余的地方都是目标图像。
PorterDuff.Mode.SRC_IN
计算方式:[Sa * Da, Sc * Da];
说明:只在源图像和目标图像相交的地方绘制源图像
和上面分析的类似,左上角是相交的地方,所以只有愿图像,其余的地方没有绘制。
PorterDuff.Mode.SRC_OUT
计算方式:[Sa * (1 - Da), Sc * (1 - Da)];
说明:只在源图像和目标图像不相交的地方绘制源图像
我们知道不相交的地方就是除了左上角之外的地方,这些地方都是目标图像。
PorterDuff.Mode.SRC_OVER
计算方式:[Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc];
说明:在目标图像的顶部绘制源图像
这也是个谁上谁下的关系,这里的原图是放在目标图像上方的,产生了叠加效果。
PorterDuff.Mode.XOR
计算方式:[Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc];
说明:在源图像和目标图像重叠之外的任何地方绘制他们,而在不重叠的地方不绘制任何内容
XOR这个模式我们在将PixelXorXfermode的时候提到过,不了解的话上去看看。
五、总结
大家一定要有这样的思维,当你想要去画一个View的时候一定要想想看这个View的图形是不是可以通过基本的几何图形混合来生成,如果可以,那么恭喜你,使用PorterDuffXfermode的混合模式你可以事半功倍!
说明:本文大部分来自:http://blog.csdn.net/aigestudio/article/details/41316141,我对原文有细小的删减,记录在此作为学习笔记之用。
From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 尊重原作者,感谢作者的分享!
详解Paint的setXfermode(Xfermode xfermode)的更多相关文章
- 详解Paint的各种set方法
一.前言 我们用set方法来设置画笔的样式,类似于我们挑选画笔画画的过程.由于上面有些方法不支持硬件加速,所以在高版本系统中可能会没有效果.因此,我们首先来看看官方废弃的方法. 下图来自:https: ...
- 详解Paint的setShader(Shader shader)
一.概述 setShader(Shader shader)中传入的自然是shader对象了,shader类是Android在图形变换中非常重要的一个类.Shader在三维软件中我们称之为着色器,其作用 ...
- 详解Paint的setPathEffect(PathEffect effect)
一.setPathEffect() 这个方法一看就和path有关,顾名思义,它就是给path设置样式(效果)的.PathEffect这个路径效果类没有具体的实现,效果是由它的六个子类实现的: 这六个子 ...
- 详解Paint的setMaskFilter(MaskFilter maskfilter)
一.setMaskFilter(MaskFilter maskfilter) setMaskFilter(MaskFilter maskfilter)是paint中的方法,它可以用来对图像进行一定的处 ...
- 详解Paint的setColorFilter(ColorFilter filter)
一.简介 setColorFilter(ColorFilter filter) 设置颜色过滤,这个方法需要我们传入一个ColorFilter参数同样也会返回一个ColorFilter实例.我们在set ...
- Android 颜色渲染(九) PorterDuff及Xfermode详解
版权声明:本文为博主原创文章,未经博主允许不得转载. Android 颜色渲染(九) PorterDuff及Xfermode详解 之前已经讲过了除ComposeShader之外Shader的全部子类 ...
- android.graphics.Paint方法setXfermode (Xfermode x...
mPaint = new Paint(); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN)); 常见的Xfermod ...
- 转载爱哥自定义View系列--Paint详解
上图是paint中的各种set方法 这些属性大多我们都可以见名知意,很好理解,即便如此,哥还是带大家过一遍逐个剖析其用法,其中会不定穿插各种绘图类比如Canvas.Xfermode.ColorFilt ...
- 安卓自定义控件(一)Canvas、Paint、Shader、Xfermode
关于自定义控件,之前就写过一篇自定义控件,上图下字的Button,图片任意指定大小,但是使用效果还是让人感觉不幸福,这次索性彻彻底底地对自定义控件做一次彻彻底底的总结. 我会花4篇博客来介绍自定义控件 ...
随机推荐
- Android快乐贪吃蛇游戏实战项目开发教程-04虚拟方向键(三)三角形按钮效果
该系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html 一.知识点讲解 当我们点击系统自带的按钮时,按钮的外观会发生变化.上篇博文中我们 ...
- D3.js学习(六)
上节我们学习了如何绘制多条曲线, 以及给不同的曲线指定不同的坐标系.在这节当中,我们会对坐标轴标签相关的处理进行学习.首先,我们来想一个问题, 如何我们的x轴上的各个标签的距离比较近,但是标签名又比较 ...
- JavaScript单线程和浏览器事件循环简述
JavaScript单线程 在上篇博客<Promise的前世今生和妙用技巧>的开篇中,我们曾简述了JavaScript的单线程机制和浏览器的事件模型.应很多网友的回复,在这篇文章中将继续展 ...
- ABP框架 - 依赖注入
文档目录 本节内容: 什么是依赖注入 传统方式的问题 解决方案 构造器注入模式 属性注入模式 依赖注入框架 ABP 依赖注入基础 注册依赖 约定注入 辅助接口 自定义/直接 注册 使用IocManag ...
- php缓冲区详解
什么是缓冲区(buffer)? 简单而言,缓冲区的作用就是,把输入或者输出的内容先放进内存,而不显示或者读取.至于为什么要有缓冲区,这是一个很广泛的问题,如果有兴趣,可以在网山找下资料. 其实缓冲区最 ...
- javascript中字符串的比较规则
弄清这个还是很重要的,在字符排序中很有用处 非空字符串 > 空字符串 从第一个字符的charCode开始比较,大的就大 所有的字符都相同,就比较长度,长的大 '0'>'' '2'>' ...
- 【.net 深呼吸】记录WCF的通信消息
前面老周给大伙伴们介绍了把跟踪信息写入日志文件的方法,今天咱们换个类似的话题来扯一下,对了,咱们就说说怎么把WCF的往来消息log下来吧. 尽管在现实生活中,我们不主张偷窥他人信息,不过,偷窥程序信息 ...
- Composer概述及其自动加载探秘
composer概述 一开始,最吸引我的当属 Composer 了,因为之前从没用过 Composer . Composer 是PHP中用来管理依赖关系的工具,你只需在自己的项目中声明所依赖的外部工具 ...
- 计数排序(counting-sort)——算法导论(9)
1. 比较排序算法的下界 (1) 比较排序 到目前为止,我们已经介绍了几种能在O(nlgn)时间内排序n个数的算法:归并排序和堆排序达到了最坏情况下的上界:快速排序在平均情况下达到该上界. ...
- JavaScript权威设计--JavaScript函数(简要学习笔记十一)
1.函数调用的四种方式 第三种:构造函数调用 如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传入函数内.这和函数调用和方法调用是一致的.但如果构造函数没有形参,JavaScri ...