精华内容
下载资源
问答
  • /、、、、、、、、、、、、、、、、、、
  • 圆角问题

    2020-12-07 11:26:29
    <div><p>设置PageStyle.MULTI_PAGE_OVERLAP跟...中间图是圆角,左右背面两张图无法展现圆角。。 有解决方法吗?谢谢</p><p>该提问来源于开源项目:zhpanvip/BannerViewPager</p></div>
  • 昨天,有设计师问到,如何用 PPT 绘制胖圆角三角形。...先看一下,胖圆角三角形长样:思考思考,如果你的话,会如何绘制呢?在弄懂胖圆角三角形之前,咱们先弄明白,圆角三角形如何绘制。在 PPT...

    6fa8398a53fa1584ef893ce31666aa5e.png

    昨天,有设计师问到,如何用 PPT 绘制胖圆角三角形。

    考虑到这是基础鼠绘技巧,而鼠绘又是很多动画与定制项目的基础。

    所以,今天给大家分享一下绘制的思路,以后好空手造素材。

    相信我,这是很多收费课程里都没有的内容,花 5 分钟看完,你的 PPT 鼠绘水平立马上一个台阶。

    先看一下,胖圆角三角形长啥样:

    a6ecea75296a9a63691d01cc43fb61d5.png

    思考思考,如果是你的话,会如何绘制呢?

    在弄懂胖圆角三角形之前,咱们先弄明白,圆角三角形如何绘制。

    在 PPT 的自带形状中,只有圆角矩形,没有圆角三角形。

    那如何绘制下图这种,圆角三角形呢?

    format,png

    这里教大家 3 种方法

    第一种方法,选择基本形状中的等腰三角形。

    按住 Shift 进行绘制,得到一个正三角形。

    813789c56377aaebd96eccd8eb21cd64.png

    之后,选中正三角形,添加线条填充,将线条的连接类型改成圆角。

    1004c9e2a686f2a6744cdc25bde3411e.png

    我们可以通过改变线条的粗细,来控制圆角的大小。

    这种方法的优点,是可以快速得到圆角三角形,而且可以任意修改圆角大小。

    但是缺点也很明显,这是假圆角三角形,不方便进行布尔运算。

    而且缩放后,还需要再次调整线条的粗细。

    第二种方法,使用圆角矩形进行拼接。

    首先,我们绘制一个圆角矩形,把黄点拉到最右边,使两侧变成半圆。

    c097b17ac448e491506ea252b61403e0.png

    再绘制两个等高的正圆,与圆角矩形的两侧对齐:

    4a883db68d2707f9633c0f3325d50ea1.png

    之后,我们横向复制两个圆角矩形,使两个正圆与他们刚好内切。

    92d6a01b574ed9560a03caa66024bb9a.png

    这一步的目的,是为了方便后面进行角度旋转。

    选中左侧与中间的圆角矩形,原位复制一份,组合起来,再逆时针旋转 60 度。

    4309b45c13ad4ece9c410057d0176bc4.png

    同理,将中间和右侧的圆角矩形,组合后顺时针旋转 60 度。

    e47740ddfe20bf9dc7211ccf40a3a7ad.png

    旋转的时候,可以按住 Shift 键,这样每旋转 15 度都能感觉到。

    接下来,取消所有组合,把四周多余的圆角矩形删掉:

    3b8d13b051e45c60787e47401a54fcf1.png

    再在中间的空白位置,绘制一个正三角形遮住。

    eb4dd593fa7f28bd901a13f61c888ab1.png

    之后全选所有形状,使用合并形状-结合,就可以得到圆角三角形了。

    76c2f82267a21137bb7c5f8f3835c95e.png

    0f0884112e2c8a166cd77155792ca537.png

    上面的操作看起来会比较麻烦,因为我用的是标准作图方法。

    如果要快速绘制的话,直接用圆角矩形旋转后,手动对齐也行。

    这种绘制方法的优点,是可以任意缩放大小。

    缺点就是画起来比较麻烦,圆角的大小受圆角矩形的高度影响,不方便修改控制。

    第三种方法,使用英豪插件快速调整。

    依旧是先绘制一个正三角形:

    813789c56377aaebd96eccd8eb21cd64.png

    之后,我们需要用到一款 PPT 插件,英豪插件。

    5f6b03292d5288d42b1eef1604e4d47a.png
    官网:https://addins.cn/yhtools/

    选中三角形,点击 编辑形状-圆角工具,设置倒圆角半径为一定的数值。

    6d59a5003f6b2f92aa9632ec72b91ec8.png

    点击确定与完成后,就得到一个圆角三角形了。

    4d5eafa8f1b0020d11142f931cf4e67e.png

    使用插件的方法,是最快速最实用的,而且圆角的大小可以随意修改。

    以上,就是绘制圆角三角形的 3 种方法。

    同样的思路,也可以拓展开,用来绘制其他圆角正多边形。

    有了基础,你再思考一下:如何去绘制胖圆角三角形呢?

    是不是有想法了?

    第一种方法,形状拼接法用起来,先来 3 个椭圆摆好。

    cb7b7aa03e42295242768c74258d78fa.png

    再画一个正三角形,把中间遮住。

    80bd00e077d99f99c7b9b78ce6294cd0.png

    全选所有形状,布尔运算结合成一个,搞定!

    3cbeb436b6f6d6622fd2f36e06abf965.png

    怎么样,有没有觉得事情简单了起来?

    等等,像这么牛逼的操作方法,我还有 3 种!

    第二种方法,曲线绕边绘制法。

    首先,先画一个正三角形,为了方便操作,去掉填充只保留线条。

    293cf67d1cfb19b1c52f339c10e4db97.png

    之后,在形状绘制里,选择曲线。

    0842e07596b9b9be2a6a6e4fcf265393.png

    依次在三角形的 3 个顶点,点击进行绘制:

    5e7a69a9e2f47aac94d0f9a42b0f7334.png

    最终形成闭合的形状时,它就变成了胖圆角三角形。

    0254de5228c62a26f6e07c35ce4b193c.png

    用这种方法绘制,同样非常快速,但是和拼接法一样,有个缺点。

    缺点就是圆角与形变的弧度,无法控制,都是自动生成的。

    第三种方法,编辑形状顶点。

    同样,还是先绘制一个正三角形。

    4394f004c7b3ff823cae4755a18d84a8.png

    选中正三角形,点击 编辑形状-编辑顶点,并选择其中一个顶点。

    6786b49ed4313c680b63980e14fed7ab.png

    这时候,会发现顶点的两侧,各有一个控制手柄。

    我们按住 Shift 不放,拖动其中一个控制手柄到下图位置:

    dfad238bad923c691779047b7a05192d.png

    这时候两个控制手柄,是在一条直线上的,而且长度一致。

    按相同的思路,调整剩下的两个顶点的控制手柄,就可以得到胖圆角三角形了。

    3a9ae1e9fca63afdf1a260421acf4ec1.png

    但是,这种绘制方法并不严谨。

    首先是 3 个顶点的控制手柄,它们的长度并不一致。

    其次,控制手柄的角度无法控制刚好 60 度,所以绘制得到的图形,并不是对称的胖圆角三角形。

    好处就是绘制简单,而且弧度可以自己控制。

    讲到这,正好拓展一下,顶点编辑的技巧。

    按住 Shift 不放,拖动控制手柄,是模拟平滑顶点,这时候两个控制手柄在一条线上,而且长度相等。

    dfad238bad923c691779047b7a05192d.png

    按住 Ctrl 不放,拖动控制手柄,是模拟直线顶点,这时候两个控制手柄在一条线上,但是手柄的长度不相等。

    84aad22437c934fddf7f6ac5a1dcaa26.png

    按住 Alt 不放,拖动控制手柄,是模拟角部顶点,这时候两个控制手柄不在一条线上,而且长度也可以任意调整。

    58e556b5d4495d2942e4e36149896cd2.png

    掌握上面的操作技巧,可以让你在鼠绘时,随心所欲的编辑顶点。

    第四种方法,使用英豪插件快速生成。

    不用多说,还是先绘制一个正三角形。

    4394f004c7b3ff823cae4755a18d84a8.png

    然后我们在三角形中,输入文字 0.5

    c88341d563fe09ef367984335246dbb2.png

    选中三角形,打开英豪插件,点击 线条相关-曲直-平滑顶点

    e4f6571dd0dcf021949fc55ede297dca.png

    点击确定后,就得到了胖圆角三角形:

    ad5dca1cb8469df54e255657ba75b4a0.png

    形状里面的数字,就是用来控制弧度大小的。

    167aaef1527f51c01d8c75f6464dc030.png

    插件的方法,简单快速标准,而且弧度可控,最为推荐。

    思路拓展一下,也可以用来绘制其他胖多边形。

    9640b549272e66f96a857351f37cc8dc.png

    7f51b57e651d9725d2b23bb0a9d31d30.png

    以上,就是绘制胖圆角三角形的 4 种方法。

    咋样,以前是不是没见过这么玩的,是不是一学就会!

    不过,这些只是 PPT 鼠绘的基础操作,基础熟练了之后,就可以去绘制各种素材了。

    比如本文头图里面的皇上,就是我用 PPT 绘制的:

    5c4174c6ad2e9ceffed4566e0a107ead.png

    皇上的身体,刚好就是胖圆角三角形。

    当然,胖圆角三角形,绝不仅仅是用来练鼠绘。

    这种非自带的形状,用在 PPT 页面中,非常有设计感。

    比如下面这套,2017 年的模板作品,就用到了这种形状,我猜有不少人见过:

    b7009003f7f550a304e391b21739abfd.png

    3bd30975daf7ad4d72a1e1df8aac5bd5.png

    fffdc1ea4fc4ae471e5b5d351d1ec28b.png

    这套模板一共有 120+ 页,质量非常高,而且可以商用。

    309c6e8d22084b91cccf12ab0dbb8d24.png

    我把它和本文的教程源文件,打包到一起了。

    1710fe954a6ac8060d5f151adc9dd907.png

    如果感兴趣,可以到资源专辑自取。

    本文首发于公众号 [自律的音律] ,欢迎联系转载。

    要是对PPT感兴趣,想要深入学习,欢迎来知乎PPT圈子交流哦。

    PPT学习圈 - 知乎www.zhihu.com
    54d5adc609f48b1f066c0fd7234673d7.png

    当然啦,也欢迎发掘我的个人主页或专栏,我有7年PPT领域的经验与故事想要分享给你。

    自律的音律zhuanlan.zhihu.com
    ae1604b91b9ded0d792dd8d3b5642b9b.png
    展开全文
  • 内容简介文章介绍ImageView(方法也可以应用到其它View)圆角矩形...很怀疑为安卓的控件不内置这样的属性(我不知道有)?之前用到的网络图片加载库(UniversalImageLoader等)都自带“圆形图片”这样的功能。这次需...

    内容简介

    文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角。思路是利用“Xfermode + Path”来进行Bitmap的裁剪。

    背景

    圆角矩形实现的方法应该很多,网上一大堆。很怀疑为啥安卓的控件不内置这样的属性(我不知道有)?

    之前用到的网络图片加载库(UniversalImageLoader等)都自带“圆形图片”这样的功能。这次需要的效果是圆角矩形,而且只有图片上面左、右两个角是圆角。然后藐似没发现有这种功能,刚好就自己实践下了。

    一个需要强调的事实就是,像ImageView这样的控件,它可以是wrap_content这样的,最终大小不定,由对应的Drawable或Bitmap资源决定其大小。另一种情况下ImageView的大小是固定的,此时图片的实际填充效果(可视范围)受到scaleType的影响,不一定和View大小一致,不过往往会保持图片宽高比例,使得最终ImageView的宽高和显示的图片是一致的。

    在画布上进行裁剪时,必须明确要操作的相关Bitmap的尺寸。由于上面的原因,根据实际ImageView大小的确定方式不同,要么是取ImageView的大小来作为整个“圆角矩形”的范围,要么是以实际展示的Bitmap的大小为准。

    下面采取自定义ImageView子类的形式提供案例来说明“Xfermode + Path”实现圆角矩形的思路。而且会以ImageView固定大小(图片填充,scaleType=fitXY)的形式,也就是说要显示的图片是完全填充ImageView的,它们一样大小。如果以Bitmap为准,那么就得自己去设法得到原本ImageView的“设置下”显示的图片的范围,然后对应的去裁剪。这里为突出重点,就不考虑那么多了(-)。

    clipPath()版本

    方法android.graphics.Canvas#clipPath(android.graphics.Path)用来沿着Path指定的路线从目前的canvas裁剪出新的区域的canvas,就是改变了画布的可绘制区域。理解上,就像你拿着剪刀沿着圆环路径裁剪画纸就可以裁剪出一个圆型画纸一样。

    Canvas类的一些API是直接绘制内容的操作,另一些是针对canvas(画布)本身做设置的。clip**系列方法就是对画布进行裁剪,之后的绘制(“可以简单地”认为之前通过canvas的绘制已经固定在画布对应存储图像的bitmap上了)都在裁剪后的区域中进行。

    使用clipPath()实现圆角矩形的完整代码如下:

    public class RoundCornerImageView1 extends ImageView {

    private float[] radiusArray = { 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f };

    public RoundCornerImageView1(Context context) {

    super(context);

    }

    public RoundCornerImageView1(Context context, AttributeSet attrs) {

    super(context, attrs);

    }

    /**

    * 设置四个角的圆角半径

    */

    public void setRadius(float leftTop, float rightTop, float rightBottom, float leftBottom) {

    radiusArray[0] = leftTop;

    radiusArray[1] = leftTop;

    radiusArray[2] = rightTop;

    radiusArray[3] = rightTop;

    radiusArray[4] = rightBottom;

    radiusArray[5] = rightBottom;

    radiusArray[6] = leftBottom;

    radiusArray[7] = leftBottom;

    invalidate();

    }

    protected void onDraw(Canvas canvas) {

    Path path = new Path();

    path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()), radiusArray, Path.Direction.CW);

    canvas.clipPath(path);

    super.onDraw(canvas);

    }

    }

    注意需要先在canvas上执行clipPath(),之后再继续绘制原本的图片,这样就保证了绘制的内容范围限制在裁剪后的“圆角矩形画布”中。

    上面方法addRoundRect()的原型如下:

    /**

    * Add a closed round-rectangle contour to the path. Each corner receives

    * two radius values [X, Y]. The corners are ordered top-left, top-right,

    * bottom-right, bottom-left

    *

    * @param rect The bounds of a round-rectangle to add to the path

    * @param radii Array of 8 values, 4 pairs of [X,Y] radii

    * @param dir The direction to wind the round-rectangle's contour

    */

    public void addRoundRect(RectF rect, float[] radii, Direction dir);

    它就是用来描述一个圆角矩形的路径。可以看到四个角都可以指定,而且还可以是不同的x,y半径。但是这里只允许圆角是圆。

    下图是一些效果图:

    d2c9bec46bb1c9cb867c768263c4b925.png

    clipPath()缺陷

    最初的版本就是这样ok了,完成任务。后来测试说是图片圆角处模糊,

    这里先给一个对比图,感受下:

    cd9dbcce3544391458c401a043fdedca.png

    我以为是网络加载的图片的Bitmap.Config引起的,改后无果。关键字“clipPath 锯齿”搜了下发现clipPath这种方式无法抗锯齿。

    后面看到StackOverflow上歪果仁的一个回答,说Xfermode可以实现。

    在sdk目录下有对应的一个关于Xfermode的使用演示:sdk\samples\android-19\ApiDemos\src\com\example\android\apis\graphics\Xfermodes.java。

    如果使用了模拟器,可以在ApiDemos > Graphics > Xfermodes中看到下面的效果:

    0df03c9bf3b6dd82bcb3dd33611e72e0.png

    后面会附上Xfermode.java的核心代码,这里说明下。矩形和圆分别是两个独立的Bitmap,上图演示了选取Xfermode的子类PorterDuffXfermode作为“Xfermode("transfer-modes" in the drawing pipeline)”时其不同混合模式得到的效果。

    把圆作为一个画框看待,那么第2行第2个效果图:SrcIn,画了一个矩形,矩形只有落在圆中的部分才最终可见。

    同样的思路,可以先做一个圆角矩形的画框——方式类似上面的clipPath()也是使用Path实现。然后让原本的图片画在这个画框上,效果就是圆角矩形的图片了。

    强调下,接下来的所有努力都是为了“抗锯齿”!应用Xfermode会使用Paint,就可以开启抗锯齿(通过Paint.ANTI_ALIAS_FLAG标志或setAntiAlias方法)。

    接下来就是用上面的示例来完成抗锯齿的圆角矩形。

    Xfermode版本

    要弄清楚apiDemo中的圆和矩形混合效果的实现,先来看下它的核心代码:

    class SampleView extends View {

    private Bitmap mSrcB; // 源位图,矩形

    private Bitmap mDstB; // 目标位图,圆

    protected void onDraw(Canvas canvas) {

    ...

    // draw the src/dst example into our offscreen bitmap

    int sc = canvas.saveLayer(x, y, x + W, y + H, null,

    Canvas.MATRIX_SAVE_FLAG |

    Canvas.CLIP_SAVE_FLAG |

    Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |

    Canvas.FULL_COLOR_LAYER_SAVE_FLAG |

    Canvas.CLIP_TO_LAYER_SAVE_FLAG);

    canvas.translate(x, y);

    canvas.drawBitmap(mDstB, 0, 0, paint);

    paint.setXfermode(sModes[i]);

    canvas.drawBitmap(mSrcB, 0, 0, paint);

    paint.setXfermode(null);

    canvas.restoreToCount(sc);

    ...

    }

    }

    成员变量:

    mSrcB: 源位图,矩形

    mDstB: 目标位图,圆

    可以看到,先绘制矩形,然后setXfermode(),然后绘制圆。

    上面的代码有一个“模板”:匹配的saveLayer()和restoreToCount()调用。

    canvas拥有layer的概念,canvas默认拥有一个初始的layer。可以通过方法int saveLayer (RectF bounds, Paint paint, int saveFlags)产生新的layer。新layer相当于一个区域为传递的bounds的“新画布”,它关联一个bitmap(an offscreen bitmap,它是完全透明的),之后的绘制操作都在此bitmap上执行。每个layer可以看做一个独立的画布,所有layer形成一个栈,栈底是初始的layer。每次在栈顶产生的新layer,任何时候都在栈顶的layer上执行绘图,调用restoreToCount()后栈顶layer出栈,其对应的bitmap的内容合并(进行像素的argb混合)到之前layer中。很显然,最后也只应该剩下最初的layer,这样保证所绘制内容都最终输出到canvas的目标bitmap中,形成最终的内容(可以假想“画布生成的内容就是bitmap”——带颜色的像素区域)。

    这里不严谨的认为:每个layer是一个canvas(画布),画布关联一个Bitmap存储最终绘制的内容。实际上不像现实中的画布或画纸,Canvas更像一个“绘图工具集”,包含直尺,圆规等绘图工具。skia文档中对SkCanvas的解释是“drawing context”——绘画环境。它提供的都是有关绘制的API,而绘制的内容会输出到Canvas的“绘制目标”——画纸,可以是Bitmap(像素集合),或者Hardware-layer(具备硬件加速的Bitmap)和DisplayList(存储绘制指令的序列而非最终的像素集合),从存储绘制结果的角度看本质是一样的。

    上面的代码中,onDraw()方法在新的layer中使用Xfermode绘图模式来画圆和矩形。原因是drawBitmap()会把参数bitmap绘制到layer对应的bitmap中(也许用词上是胡说八道,但这样可以理解吧?),Xfermode模式下后续drawBitmap()方法会以当前layer的“整个区域的内容”作为混合操作的参考bitmap,所以为了不让之前layer已有内容对混合产生影响,就使用一个全新的layer——也就是全新的bitmap来进行混合绘制,最终再合并回去。

    下面把各个方法的API介绍简单罗列下,重点是Xfermode类和PorterDuffXfermode类。

    方法saveLayer()

    原型如下:

    /**

    * This behaves the same as save(), but in addition it allocates an

    * offscreen bitmap. All drawing calls are directed there, and only when

    * the balancing call to restore() is made is that offscreen transfered to

    * the canvas (or the previous layer). Subsequent calls to translate,

    * scale, rotate, skew, concat or clipRect, clipPath all operate on this

    * copy. When the balancing call to restore() is made, this copy is

    * deleted and the previous matrix/clip state is restored.

    *

    * @param bounds May be null. The maximum size the offscreen bitmap

    * needs to be (in local coordinates)

    * @param paint This is copied, and is applied to the offscreen when

    * restore() is called.

    * @param saveFlags see _SAVE_FLAG constants

    * @return value to pass to restoreToCount() to balance this save()

    */

    public int saveLayer(RectF bounds, Paint paint, int saveFlags)

    在API文档中还有下面的说明:

    public int saveLayer (RectF bounds, Paint paint, int saveFlags);

    This behaves the same as save(), but in addition it allocates and redirects drawing to an offscreen bitmap.

    Note: this method is very expensive, incurring more than double rendering cost for contained content. Avoid using this method, especially if the bounds provided are large, or if the CLIP_TO_LAYER_SAVE_FLAG is omitted from the saveFlags parameter. It is recommended to use a hardware layer on a View to apply an xfermode, color filter, or alpha, as it will perform much better than this method.

    All drawing calls are directed to a newly allocated offscreen bitmap. Only when the balancing call to restore() is made, is that offscreen buffer drawn back to the current target of the Canvas (either the screen, it's target Bitmap, or the previous layer).

    Attributes of the Paint - alpha, Xfermode, and ColorFilter are applied when the offscreen bitmap is drawn back when restore() is called.

    上面说到在使用Xfermode时,可以开启硬件加速(hardware layer)来直接绘制,此时不需要产生新的layer,会具有更好的性能,后面会给出这种实现。

    方法restoreToCount()

    原型如下:

    /**

    * Efficient way to pop any calls to save() that happened after the save

    * count reached saveCount. It is an error for saveCount to be less than 1.

    *

    * Example:

    * int count = canvas.save();

    * ... // more calls potentially to save()

    * canvas.restoreToCount(count);

    * // now the canvas is back in the same state it was before the initial

    * // call to save().

    *

    * @param saveCount The save level to restore to.

    */

    public native void restoreToCount(int saveCount);

    根据约定,在调用saveLayer()后,执行restoreToCount()将新layer中的内容合并回之前layer。

    PorterDuffXfermode

    方法android.graphics.Paint#setXfermode用来为paint设置Xfermode。之后使用此paint绘制的图像就会应用具体Xfermode子类所表示的“模式”。

    类Xfermode的说明:

    Xfermode is the base class for objects that are called to implement custom "transfer-modes" in the drawing pipeline. The static function Create(Modes) can be called to return an instance of any of the predefined subclasses as specified in the Modes enum. When an Xfermode is assigned to an Paint, then objects drawn with that paint have the xfermode applied.

    Xfermode表示要在“绘制管线中使用的颜色传递模式”。概括来说,每一次绘图操作(drawXxx)底层都执行一次绘制管线,通常要经过:路径生成(Path Generation)、光栅化(Rasterization)、着色(Shading)和传递(Transfer)四个阶段。管线操作的输入就是draw**的输入,包括方法对应绘制图形图像的参数信息,以及canvas layer关联的目标bitmap (下面用Dst Image表示)。

    在Transfer阶段,会根据之前阶段产生的“source image”和Dst Image生成一个intermediate image(中间图片)。过程是把每个(x,y)处的source image和Dst Image的像素颜色值使用指定的传递模式(Xfermode,如果未指定,默认是PorterDuffXferMode(SRC_OVER))对应的函数,得到结果color,然后传递给中间图片作为其(x,y)的color,最后中间图片和Dst Image再进行混合(使用Mask),结果就是修改后的Dst Image。

    Xfermode是一个基类,它的子类表示实际的颜色传递模式。子类PorterDuffXfermode表示:Porter/Duff 颜色混合算法,这里有篇文章Porter/Duff描述了它。在ApiDemo中给出了Porter/Duff模式支持的16种不同混合效果。

    代码实现

    上面介绍了ApiDemo中核心代码片段的含义,接下来就继续沿用其saveLayer()、ResetoreToCount()以及Xfermode()这几个步骤来实现圆角矩形。

    得到Dst Image

    本身要绘制的图像就是Dst Image,在ImageView的onDraw方法中,super.onDraw(canvas)会将需要绘制的内容绘制到传递的canvas中,这里为了得到对应的bitmap,可以产生一个新的Canvas对象然后把它作为ImageView.onDraw的输出目标:

    // 得到原始的图片

    final int w = getWidth();

    final int h = getHeight();

    Bitmap bitmapOriginal = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

    Canvas c = new Canvas(bitmapOriginal);

    super.onDraw(c);

    上面的w、h是原始图片的宽、高,根据文章开始的假定,就是ImageView的宽高。bitmapOriginal作为super.onDraw的绘制结果。这样就得到了“Xfermode中的Dst Bitmap”。

    得到Src Bitmap - 圆角矩形

    为了四个角可配,继续使用Path来得到圆角矩形,重要的是为Paint设置ANTI_ALIAS_FLAG标志开启抗锯齿:

    // 四个角的x,y半径

    private float[] radiusArray = { 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f };

    private Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private Bitmap makeRoundRectFrame(int w, int h) {

    Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);

    Canvas c = new Canvas(bm);

    Path path = new Path();

    path.addRoundRect(new RectF(0, 0, w, h), radiusArray, Path.Direction.CW);

    Paint bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    bitmapPaint.setColor(Color.GREEN); // 颜色随意,不要有透明度。

    c.drawPath(path, bitmapPaint);

    return bm;

    }

    在新layer中绘制

    if (bitmapFrame == null) {

    bitmapFrame = makeRoundRectFrame(w, h);

    }

    int sc = canvas.saveLayer(0, 0, w, h, null, Canvas.ALL_SAVE_FLAG);

    canvas.drawBitmap(bitmapFrame, 0, 0, bitmapPaint);

    // 利用Xfermode取交集(利用bitmapFrame作为画框来裁剪bitmapOriginal)

    bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

    canvas.drawBitmap(bitmapOriginal, 0, 0, bitmapPaint);

    bitmapPaint.setXfermode(null);

    canvas.restoreToCount(sc);

    上面的saveLayer()接收的saveFlags是和canvas已设置的状态相关的,canvas需要恢复哪些方面的属性,就需要标记对应SAVE_FLAG来保存相应的状态。

    因为上面对Paint开启了抗锯齿,最终得到的圆角矩形就不像clipPath那种会在圆角处产生模糊。

    ac28173e7632d1309d22ac3c0d5f37e8.png

    Hardware Layer

    根据saveLayer方法的文档介绍,可以去掉saveLayer()/restoreToCount()的调用,只需要在onDraw()中开启硬件加速就可以实现相同的目标了,性能会更好:

    setLayerType(LAYER_TYPE_HARDWARE, bitmapPaint);

    // 利用Xfermode取交集(利用bitmapFrame作为画框来裁剪bitmapOriginal)

    canvas.drawBitmap(bitmapFrame, 0, 0, bitmapPaint);

    bitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

    canvas.drawBitmap(bitmapOriginal, 0, 0, bitmapPaint);

    bitmapPaint.setXfermode(null);

    结论

    上面分别给出了clipPath和Xfermode方式实现圆角矩形的方式,根据场景不同——在什么地方来实现需要的圆角矩形——其它等像基于shader的方式也许是更好的选择。

    强调下,上面代码限制ImageView和它展示的内容必须是同样大小的,否则就以实际显示图片的Rect作为“圆角矩形画框”的Rect。

    Android有关2D和3D的很多操作,像上面的clipPath和Xfermode,底层都是native方式执行的,framework层几乎只是很薄的C++包装。而且是比较专业的知识了,到底要了解多少,就看自己的app的需求,以及兴趣了。

    Canvas Api的底层实现是Skia,之后引入了opengl es的实现(HWUI),后者支持硬件加速。

    (本文使用Atom编写)

    展开全文
  • Android 实现圆角按钮

    2017-11-08 10:21:39
    首先扯点别的:这两天一直浑浑噩噩的,不知道干,什么也不想干,整日胡思乱想。如今已春天了,已经过了惊蛰(虽然即墨这几天有点冷),可是我还是没有从一种行尸走肉的麻木中醒过来,不知道自己在干什什么,以后...

    首先扯点别的:这两天一直浑浑噩噩的,不知道干啥,什么也不想干,整日胡思乱想。如今已是春天了,已经过了惊蛰(虽然即墨这几天有点冷),可是我还是没有从一种行尸走肉的麻木中醒过来,不知道自己在干什什么,以后将要都走向哪里。

    1. 进入正题,今天简单的演示一下Android中如何实现圆角按钮。使用了selector和shape.先看效果吧,感觉效果不是你想要的,果断pass掉。

    这里写图片描述

    1 xml布局的第一个,就是一个Button.,其他的都是TextView

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    <!--注意 android:background="@drawable/btn_selector"-->
        <Button
            android:id="@+id/Button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@drawable/btn_selector" 
            android:text="@string/hello_world" />
    
    </RelativeLayout>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2 注意到上面的Button的background属性

    android:background="@drawable/btn_selector" 
    其中的btn_selector是一个自定义的xml文件,继续看这个文件
    • 1
    • 2

    3在工程的res目录下面新建一个forlder命名成drawable(小写英文的,注意别写错了),然后在drawable目录下新建一个selector文件

    btn_selector.xml,大家应该秒懂这个文件的内容和意思吧!当按钮正常没有被按下的时候显示一个背景,按下的时候则显示另外一个颜色的背景,这样可以使用户得知按钮被按下了。

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    
        <!-- Button正常状态下的背景 -->
        <item android:drawable="@drawable/btn_bg_normal" android:state_pressed="false"/>
        <!-- Button按下时的背景 -->
        <item android:drawable="@drawable/btn_bg_pressed" android:state_pressed="true"/>
    </selector>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4 从btn_selector.xml文件中大家又发现了btn_bg_normal和btn_bg_pressed,这两个文件也是在drawable目录下的

    4.1 在drawable 目录下新建两个 shape文件分别是btn_bg_normal.xml,和btn_bg_pressed.xml文件

    btn_bg_normal.xml

    <?xml version="1.0" encoding="utf-8"?>
    <!-- 按钮正常的时候的背景 -->
    <!-- shape的默认形状是rectangle,还有oval(椭圆),line(线),ring(圆环),我就用过rectangle,其他的大家可以试一试 -->
    
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- 矩形的圆角弧度 -->
        <corners android:radius="10dp" />
        <!-- 矩形的填充色 -->
        <solid android:color="#FF4081" />
    
        <!-- 矩形的边框的宽度,每段虚线的长度,和两段虚线之间的颜色和颜色 -->
        <stroke
            android:width="1dp"
            android:dashWidth="8dp"
            android:dashGap="4dp"
            android:color="#4eb621" />
    </shape>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    btn_bg_pressed.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- 矩形的圆角弧度 -->
        <corners android:radius="10dp" />
        <!-- 矩形的填充色 -->
        <solid android:color="#3F51B5" />
        <!-- 矩形的边框的宽度,每段虚线的长度,和两段虚线之间的颜色和颜色 -->
        <stroke
            android:width="1dp"
            android:color="#4eb621"
            android:dashGap="4dp"
            android:dashWidth="8dp" />
    </shape>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    两点注意: 
    注意 stroke 是指shape的边界线

      <stroke
            android:width="1dp"
            android:dashWidth="8dp"
            android:dashGap="4dp"
            android:color="#4eb621" />
    • 1
    • 2
    • 3
    • 4
    • 5

    如果希望边界线是实线而不是虚线的话,可以象下面这样写。

    <stroke
            android:width="1dp"
            android:color="#4eb621" />
    • 1
    • 2
    • 3

    注意如果要实现只有左边是圆角,右边还是直角这种类似的背景的话,可以如下设置:

    <corners 
                    android:topLeftRadius="20dp"
                    android:bottomLeftRadius="20dp"
                    android:topRightRadius="0dp" 
                    android:bottomRightRadius="0dp"  />
    • 1
    • 2
    • 3
    • 4
    • 5

    具体设置corners 每个角的角度

    drawable gradient 渐变背景色。

    <gradient
      android:angle="integer"
      android:centerX="Float"
      android:centerY="Float"
      android:centerColor="integer"
      android:startColor="color"
      android:endColor="color"
      android:gradientRadius="integer"
      android:type=["linear"|"radial"|"sweep"]
      android:usesLevel=["true"|"false"]
      />
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    angle:角度,当 android:type=“linear”时有效 ,亿45度为单位,逆时针方向旋转
    centerX:Float。渐变色中心的 X 相对位置( 0-1.0 )。当 android:type=“linear”时无效 
    centerY:Float。渐变色中心的 Y 相对位置( 0-1.0 )。当 android:type=“linear”时无效 
    centerColor:color。可选的颜色,出现在 start 和 end 颜色之间。 
    gradientRadius:Float。渐变色的半径。当 android:type=“radial” 时有效。 
    startcolor:开始的颜色 
    endcolor:结束的颜色 
    type:渐变色的样式。有效值为: 
    “linear”:线性渐变,默认值 
    “radial”:环形渐变。 start 颜色是处于中间的颜色 
    “sweep”:扇形渐变 
    useLevel:Boolean。“ true ”表示可以当作 LevelListDrawable 使用(没搞懂是什么意思)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    layer-list 使用 
    图片来自:http://blog.csdn.net/pcaxb/article/details/47781547 
    这里写图片描述

    例子:如果我们想给一个TextView 添加这样一个背景,一层背景是白色的,另外一层是蓝色的但是只露出来一部分,就可以使用layer-list实现。

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    
        <!--上面的为背景的底层-->
        <item>
            <shape android:shape="rectangle">
                <solid android:color="@color/colorPrimary" />
            </shape>
        </item>
    
        <!--背景上面的图层 让底部的背景露出来4dp的高度-->
        <item android:bottom="4dp">
            <shape android:shape="rectangle">
                <solid android:color="@color/colorAccent" />
            </shape>
        </item>
    </layer-list>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    最后来一张图 这才是重点啊,哈哈。

    这里写图片描述 
    这里只显示了部分用法,还有更多用法以后用到再研究。

    源代码 https://github.com/humanheima/ShapeSelectordemo

    结尾:参考链接 
    【1】http://www.jianshu.com/p/f67d8610fcda 
    【2】http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/u013293125/article/details/50359556 
    【3】http://blog.csdn.net/pcaxb/article/details/47781547

    展开全文
  • 前言话不说,先亮出效果图:最近公司UI设计了一个这样的tab切换的样式,刚一看到UI设计图,感觉还是不错滴。但是几秒钟后下意识想到,这个效果,Android自带的 tablayout 控件应该实现不了这效果呢。顿时一脸茫然...

    前言

    啥话不说,先亮出效果图:

    ddb2589856579186fb5315931629ca72.gif

    最近公司UI设计了一个这样的tab切换的样式,刚一看到UI设计图,感觉还是不错滴。但是几秒钟后下意识想到,这个效果,Android自带的 tablayout 控件应该实现不了这效果呢。顿时一脸茫然,我还要自定义一个不成!但是这个弧度怎么搞…此时有的小伙伴可能会想,自定义view太麻烦,不如让UI直接把这个弧度切出来,不是一共就三个tab项嘛,Textview,ImageView… 这样横着排起来,然后做适当的显示和隐藏不就行啦。是的,确实是可以,但是作为一个优秀的开发人员。我们还是要优选自定义view滴。

    思路分析

    (1) 由效果图,我们很容易分析出,不管tab项一共几个,无非就这三种情况。
    草图如下:
    c78246709b09d5ede2ca976fb28f239e.png(2) 无论是哪种情况,首先我们需要画出一个背景矩形,这个比较简单。(3)下面就是曲线的画法,草图中也已经标注了,很明显我需要2个控制点,那就需要用到三阶贝塞尔曲线啦!cubicTo(4)画出图形后,点击事件如何响应处理呢?我们在 onTouchEvent 是能获取到点击控件后x,y坐标的,判断x的坐标是在哪个tab项的范围内,我们就认为点击了那个tab项,就可以了。(5)控件的圆角的如何实现呢?canvas的 范围裁切 就可以啦。

    代码实现

    思路梳理好了,那我们就写代码吧:情况一(关键代码):
     //最左边的图形            Path pathLeft = new Path();            pathLeft.lineTo(textWidth, 0);            pathLeft.cubicTo(textWidth + arcControlX, arcControlY, textWidth + arcWidth - arcControlX, viewHeight - arcControlY, textWidth + arcWidth, viewHeight);            pathLeft.lineTo(0, viewHeight);            pathLeft.lineTo(0, 0);            paint.setColor(selectColor);            canvas.drawPath(pathLeft, paint);
    步骤说明:
    1. 首先我们的起始点坐标是(0,0),到坐标(textWidth, 0) 画一条直线;

    2. 然后三阶贝塞尔曲线,2个控制点的坐标1(textWidth + arcControlX,arcControlY),坐标2(textWidth + arcWidth - arcControlX,viewHeight - arcControlY),结束的坐标(textWidth + arcWidth,viewHeight);

    3. 最后画直线到坐标点(0, viewHeight),再到最终的原点(0, 0)。

    到这里一个封闭的路径,就画好啦。情况二和情况三也是同样的道理,我也不再废话了。情况二(关键代码):
     //中间的图形            Path pathCenter = new Path();            pathCenter.moveTo(tabPosition * textWidth + tabPosition * arcWidth, 0);            pathCenter.cubicTo(tabPosition * textWidth + tabPosition * arcWidth - arcControlX, arcControlY, tabPosition * textWidth + tabPosition * arcWidth - arcWidth + arcControlX, viewHeight - arcControlY, tabPosition * textWidth + tabPosition * arcWidth - arcWidth, viewHeight);            pathCenter.lineTo(tabPosition * textWidth + tabPosition * arcWidth + textWidth + arcWidth, viewHeight);            pathCenter.cubicTo(tabPosition * textWidth + tabPosition * arcWidth + textWidth + arcWidth - arcControlX, viewHeight - arcControlY, tabPosition * textWidth + tabPosition * arcWidth + textWidth + arcControlX, arcControlY, tabPosition * textWidth + tabPosition * arcWidth + textWidth, 0);            pathCenter.lineTo(tabPosition * textWidth + tabPosition * arcWidth, 0);            paint.setColor(selectColor);            canvas.drawPath(pathCenter, paint);
    情况三(关键代码):
      //最右边的图形            Path pathRight = new Path();            pathRight.moveTo(viewWidth, 0);            pathRight.lineTo(viewWidth - textWidth, 0);            pathRight.cubicTo(viewWidth - textWidth - arcControlX, arcControlY, viewWidth - textWidth - arcWidth + arcControlX, viewHeight - arcControlY, viewWidth - textWidth - arcWidth, viewHeight);            pathRight.lineTo(viewWidth, viewHeight);            pathRight.lineTo(viewWidth, 0);            paint.setColor(selectColor);            canvas.drawPath(pathRight, paint);
    tabtext的绘制(关键代码):
    for (int i = 0; i < tabTextList.size(); i++) {            String strTabText = tabTextList.get(i);            Rect rectText = new Rect();            textPaint.getTextBounds(strTabText, 0, strTabText.length(), rectText);            int strWidth = rectText.width();            int strHeight = rectText.height();            if (i == 0) {                canvas.drawText(strTabText, (textWidth + arcWidth / 2) / 2 - strWidth / 2, viewHeight / 2 + strHeight / 2, textPaint);            } else if (i == tabTextList.size() - 1) {                canvas.drawText(strTabText, viewWidth - (textWidth + arcWidth / 2) / 2 - strWidth / 2, viewHeight / 2 + strHeight / 2, textPaint);            } else {                canvas.drawText(strTabText, textWidth * i + arcWidth * (i - 1) + (textWidth + 2 * arcWidth) / 2 - strWidth / 2, viewHeight / 2 + strHeight / 2, textPaint);            }        }
    tab点击处理(关键代码):
    @Override    public boolean onTouchEvent(MotionEvent event) {        boolean isHandleClick = false;//是否处理点击事件        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                float x = event.getX();                float y = event.getY();                System.out.println("YPKTabLayoutView.onTouchEvent x=" + x + " y=" + y);                for (int i = 0; i < tabNumber; i++) {                    if (x <= ((i + 1) * textWidth + i * arcWidth + arcWidth / 2)) {//点击的第一个按钮                        tabPosition = i;                        if (onTabClickListener != null) {                            onTabClickListener.tabSelectedListener(tabPosition);                        }                        invalidate();                        isHandleClick = true;                        break;                    }                }                return isHandleClick;            case MotionEvent.ACTION_MOVE:                break;            case MotionEvent.ACTION_UP:                break;        }        return super.onTouchEvent(event);    }
    步骤说明:我们在 onTouchEvent方法中, 首先获取到点击控件后x,y坐标,然后for循环判断x的坐标是在哪个tab项的范围内,最后在哪个范围内,我们就认为点击了那个tab项,回调对应的 tabPosition 就可以了。

    远程依赖使用

    一:添加依赖

    Add it in your root build.gradle at the end of repositories:

    allprojects {    repositories {        ...        maven { url 'https://jitpack.io' }    }}

    Add the dependency

    dependencies {      implementation 'com.github.dacaoyuan:YPKTabDemo:1.0.2'}

    二:在xml布局中添加

            android:id="@+id/mYPKTabLayoutView"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_margin="10dp"        app:view_bg_corners="0"        app:arcControlX="30" />

    三:代码中

    val tabTextList: MutableList = ArrayList()        tabTextList.add("推荐学习");        tabTextList.add("企业学院");        tabTextList.add("我的关注");        mYPKTabLayoutView.setTabTextList(tabTextList);        mYPKTabLayoutView.addTabSelectedListener { tabPosition ->            val makeText =                Toast.makeText(                    this@MainActivity,                    "点击了第" + tabPosition + "项",                    Toast.LENGTH_SHORT                )            makeText.setGravity(Gravity.CENTER, 0, 0);            makeText.show();        }

    属性说明

    25af009a25141c1e38f27fa15d5f5d65.png

    源码地址:https://github.com/dacaoyuan/YPKTabDemo到这里就结束啦往期精彩回顾
    • Android实现短信验证码自动填充功能

    • Android仿echo精美弹幕功能

    • Android实现头像重叠排列功能

    • Android仿QQ个性标签功能

    • Android仿QQ侧滑删除的功能

    39d748bc855e9657cf5d8d376c8f75ab.png

    abeb5756c604ef0ed82b95a53f49a582.png

    展开全文
  • 前言话不说,先亮出效果图:最近公司UI设计了一个这样的tab切换的样式,刚一看到UI设计图,感觉还是不错滴。但是几秒钟后下意识想到,这个效果,Android自带的 tablayout 控件应该实现不了这效果呢。顿时一脸茫然...
  • Android 实现圆角按钮(selector和shape的简单用法)

    万次阅读 多人点赞 2016-03-02 22:00:26
    首先扯点别的:这两天一直浑浑噩噩的,不知道干,什么也不想干,整日胡思乱想。如今已春天了,已经过了惊蛰(虽然即墨这几天有点冷),可是我还是没有从一种行尸走肉的麻木中醒过来,不知道自己在干什什么,以后...
  • 项目中有用到圆角图片,放到RecyclerView里面,总是不对,圆角效果失效了,不放到RecyclerView就正常,折腾了很久,才发现RecyclerView设置了软件层的原因。为会这样没研究明白,这个内容还是很深的。 推荐看...
  • 在处理input的问题时,一般不想要input的原来的样式,一般就直接处理 border: none; outline: none; background: transparent;...但是最近在写一个微信公众号的...后来同事一测(IOS),就告诉我,input是圆角,且...
  • 写页面时候遇到一个效果,这很常见的一个tab切换,但是样式上不是常见的...不同于矩形的直角直线,这里效果上是圆角加斜线,一个容器无法实现的,可以使用伪类构建一个平行四边形,再做拼接。代码如下:class...
  • 需求:从网络加载图片,并轮播显示,显示区域为圆角矩形。就这么个简单的需求,这里要快速开发。我们可以选择轮播框架RollPagerView与图片加载框架UniversalImageloader来实现。1.环境配置,主要加载依赖。开发...
  • 内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形...很怀疑为安卓的控件不内置这样的属性(我不知道有)? 之前用到的网络图片加载库(UniversalImageLoader等)都自带“圆形图片”这样的功能...
  • 一次偶然的机会,让我发现了新大陆RoundedBitmapDrawable,不难看出他的作用是圆角图片。今天来看下史上最简单的方式,为说最简单呢,因为系统已经提供了api,你只需一句话调用就完事,你说能不简单吗。。先看如何...
  • shader是啥?干嘛用的? 点击打开链接 shader咋用? 举例 bitmapShader : public class BitmapShaderView extends ImageView { private Paint paint; private Bitmap bitmap; public BitmapShaderView...
  • 首先扯点别的:这两天一直浑浑噩噩的,不知道干,什么也不想干,整日胡思乱想。如今已春天了,已经过了惊蛰(虽然即墨这几天有点冷),可是我还是没有从一种行尸走肉的麻木中醒过来,不知道自己在干什什么,以后...
  • hello,大家好啊,我summer...总不该玩PPT吧我一般呢,都去看看吃播啊,逛逛B站啊,刷刷知乎啊的。这不,之前打开知乎,看到了这个,顺手就截了个屏:瞬间就联想到一个问题,这个怎么做成的。相信凭借各位...
  • 话说为拖到现在才写这篇文章,也一出辛酸泪。其实之前准备给大家测评几款了,但是团队开会讨论了下。等几天再看看,万一其他几款也停运了呢?此话一出,万籁俱寂。今天,小公举找到了四个市场上硕果仅存的新媒体...
  • 导读 汽车行业的朋友,如果没听说过CATIA,相信一定不敢自称“老司机”! 起源于航空航天业的CATIA,一问世之后就因其强大的功能以得到各行业的认可,特别在汽车行业,已成为各大顶尖汽车制造商所采用的核心系统。...
  • 最近需要写些文档,于是乎又捡起了Visio2013,不过,打开的时候,已经授权码过期了,网上搜了一个,有需要的可自行下载: ...至于什么杀毒软件报错的,自己关闭杀软或者添加为白名单即可。 看下图中,我
  • 这样,就有了两套桌面主题,一套的要求六边形的图标展示,文件夹预览3个图标拼接(见下图),另一套就是比较常见的圆角图标展示加上文件夹9个预览图排列。先上效果图压阵六边形图标桌面圆角图标桌面需求分析首先...
  • 前言:折腾了半天圆角,发觉border-...以下是找到的相当不错的一篇css样式权重讲解的,清晰明了,看完就懂是啥了。 永记在心:important > 内联 > ID > 类|属性|伪类 > 标签|伪元素 > 通配符 >...
  • css3---新特性

    2017-03-29 10:55:28
    前两天在看网易的面试题,有一道考察对css3新特性的background-clip等。表示我还是乖乖的去查了手册...对于那时候只自学了css2的我来说,圆角啥的简直难到我了。。依稀记得慕课网上教育我,用圆角,找个图片加背景
  • .9png图片的制作

    千次阅读 2017-01-05 10:49:42
    所以叫.9png图片呢,就是那个类似QQ聊天的气泡你造吗,它的背景个图片,但是角是圆角,所以这种图片可以用某种不可描述的方法设置之后,只拉伸横向竖向的一部分而让那些圆角啦,小尾巴之类的不动,这就是.9png...
  • 前言图片显示,说简单也简单,说难也难,在...,找各种资料,最终只有一个答案,GDI+,GDI+不知道是啥玩意怎么办,在找资料学,最后会发现,显示一个PNG图片,需要十几行左右,还不包括有圆角等。(这里没说C#)。但...
  • ,找各种资料,最终只有一个答案,GDI+,GDI+不知道是啥玩意怎么办,在找资料学,最后会发现,显示一个PNG图片,需要十几行左右,还不包括有圆角等。(这里没说C#)。 但今天说的是GDI,GDI+作为GDI的扩展,增强了很...
  • CSS滑动门特性

    千次阅读 2016-04-05 20:16:26
     看了css,原来以为没技术含量,狂背就成了,现在才发现,背是不行地……最起码光背是不行地,看到这个被css设计师们称为“滑动门”... 需求是有不同长度的按钮,却要求同一种背景……要是图片缩放的话,圆角是
  • 前言 最近又弄了弄二维码,做个记录。用的ZBar,原因灵敏度相较于Zxing更好。...其实也没改,就是把边框改为圆角了。具体在cn.bingoogolapple.qrcode.core.ScanBoxView: 代码 /*...
  • 看了css,原来以为没技术含量,狂... 需求是有不同长度的按钮,却要求同一种背景……要是图片缩放的话,圆角是会变形地…… 所以应该先把图片切成两部分 和 ,然后呢…… <styletype="text/css">&l...

空空如也

空空如也

1 2 3
收藏数 57
精华内容 22
关键字:

圆角是啥