美文网首页
view基础学习

view基础学习

作者: 有点健忘 | 来源:发表于2019-01-07 13:58 被阅读17次

https://blog.csdn.net/harvic880925/article/details/50995268

如何让文字居中显示

如题,在自定义view中,如果要drawText,要求文字在控件的正中心,这之后咋做?


image.png

个人的测试,首先以任意中文字来获取文字的高度

var text="好里"
p.getTextBounds(text,0,text.length,bounds)

完事在获取实际文字的高度,分两种处理

  1. 比中文字的高度小的,或者等于,那么基线就设置为中心点往下如下数值
    比如字母bdtl, gpy ,这两种都比中文高度小,可如果放一起就比中文字高度大了
val offset=bounds.height()/2-bounds.bottom
  1. 比中文字高度大的
    这种一般是英文字母,bg之类的,也就是有字母在基线上的b,d,t,l,也有在基线下g,p,y之类的
 offset=bounds.height()/2-this.descent.roundToInt()

paint的属性

常见的几种

        p.apply {
            strokeWidth=20f 画笔的粗细,宽度
            textAlign=Paint.Align.CENTER//对drawText有效,文字从哪里开始画
            textSize=33f//文字的字体大小
            style=Paint.Style.FILL_AND_STROKE
            color=Color.parseColor("#550000ff") //画笔的颜色
        }
image.png

以画个圆圈为例

canvas.drawCircle(width/2f,height/2f,100f,p)

如上图style的3种解释如下

    public enum Style {
        /**
         * Geometry and text drawn with this style will be filled, ignoring all
         * stroke-related settings in the paint.
         */
        FILL            (0),//圈内部
        /**
         * Geometry and text drawn with this style will be stroked, respecting
         * the stroke-related fields on the paint.
         */
        STROKE          (1), 画笔宽度平分,一半在圈内,一半在圈外
        /**
         * Geometry and text drawn with this style will be both filled and
         * stroked at the same time, respecting the stroke-related fields on
         * the paint. This mode can give unexpected results if the geometry
         * is oriented counter-clockwise. This restriction does not apply to
         * either FILL or STROKE.
         */
        FILL_AND_STROKE (2); 上边两个加起来的就是,圆圈内部,加上画笔宽度的一半
    }

Aligin 下图,x坐标为中心线


image.png
    public enum Align {
        /**
         * The text is drawn to the right of the x,y origin
         */
        LEFT    (0),//文字在x坐标的右边
        /**
         * The text is drawn centered horizontally on the x,y origin
         */
        CENTER  (1),//文字的中心在x坐标
        /**
         * The text is drawn to the left of the x,y origin
         */
        RIGHT   (2);//文字的右边在x坐标上

        private Align(int nativeInt) {
            this.nativeInt = nativeInt;
        }
        final int nativeInt;
    }

paint.setShadowLayer,效果图上边有

radius:阴影文字的模糊半径,必须大于0,小于等于0的话这个就无效了。不能太大,稍微大点就模糊的没有了。。
dx:阴影文字相对原始文字在x轴的偏移量,和坐标轴方向一致,大于0自然是往右
dy:y轴方向的,同上
shadowColor:阴影文字的颜色

public void setShadowLayer(float radius, float dx, float dy, int shadowColor)

drawline
drawpoint
drawrect
这些简单的就不说了
drawOval 其实就是在一个矩形内,也是需要4个点,或者一个rect
圆弧,椭圆的一部分,rect就是椭圆的范围了,也可以是4个点。
startAngle:起始角度,x轴右侧为0度,顺时针为正
sweepAngle:经过的角度,最终的角度就是起始角度加上这个
useCenter:是否把圆弧和中心点连接起来。

public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
            @NonNull Paint paint)


//代码如下,效果图在下边
        val rect=RectF(width/2f-100,height/2f-100,width/2f+100,height/2f+100)
        p.color=Color.RED
        canvas.drawArc(rect,0f,90f,false,p)

        p.color=Color.BLUE
        canvas.drawArc(rect,0f,-90f,true,p)//圆弧和中心点连接起来了。
image.png

Cap

处理线条的起点和终点的效果的,默认的BUTT,没效果

    /**
     * The Cap specifies the treatment for the beginning and ending of
     * stroked lines and paths. The default is BUTT.
     */
    public enum Cap {
        /**
         * The stroke ends with the path, and does not project beyond it.
         */
        BUTT    (0),
        /**
         * The stroke projects out as a semicircle, with the center at the
         * end of the path.
         */
        ROUND   (1),以圆弧结尾,就是凸出去一个半圆
        /**
         * The stroke projects out as a square, with the center at the end
         * of the path.
         */
        SQUARE  (2);这个是凸出去一个矩形,凸出去的就是画笔宽度的一半,下图可以看到效果
    }
        p.strokeWidth=15f
        p.style=Paint.Style.FILL
        
        p.strokeCap=Paint.Cap.BUTT
        canvas.drawLine(10f,20f,200f,20f,p)
        
        p.strokeCap=Paint.Cap.ROUND
        canvas.drawLine(10f,40f,200f,40f,p)
        
        p.strokeCap=Paint.Cap.SQUARE
        canvas.drawLine(10f,60f,200f,60f,p)
image.png

JOIN

处理线条相交的地方,有3种,看效果图就知道了


image.png
    /**
     * The Join specifies the treatment where lines and curve segments
     * join on a stroked path. The default is MITER.
     */
    public enum Join {
        /**
         * The outer edges of a join meet at a sharp angle
         */
        MITER   (0),
        /**
         * The outer edges of a join meet in a circular arc.
         */
        ROUND   (1),
        /**
         * The outer edges of a join meet with a straight line
         */
        BEVEL   (2);
    }

测试代码如下

        val path=Path().apply {
            moveTo(20f,20f)
            lineTo(80f,20f)
            lineTo(80f,100f)
            close()
        }
        p.style=Paint.Style.STROKE
        p.strokeJoin=Paint.Join.MITER
        canvas.drawPath(path,p)

        path.offset(100f,0f)
        p.strokeJoin=Paint.Join.ROUND
        canvas.drawPath(path,p)

        path.offset(100f,0f)
        p.strokeJoin=Paint.Join.BEVEL
        canvas.drawPath(path,p)

setStrokeMiter

个人测试,感觉这个是对它生效的p.strokeJoin=Paint.Join.MITER而且画笔的style不是是FILL.
就是对于尖角的处理,小点的话感觉和BEVEL差不多了,稍微大点就看不出效果了

   /**
     * Set the paint's stroke miter value. This is used to control the behavior
     * of miter joins when the joins angle is sharp. This value must be >= 0.
     *
     * @param miter set the miter limit on the paint, used whenever the paint's
     *              style is Stroke or StrokeAndFill.
     */
    public void setStrokeMiter(float miter)
        p.strokeMiter=2f
        p.style=Paint.Style.STROKE
        p.strokeJoin=Paint.Join.MITER

其他文字相关

p.textSkewX=0.5f//文字的倾斜角度,我们平时说的斜体字,是 -0.25朝右倾斜的

paint.setUnderlineText(true);//设置下划线
paint.setStrikeThruText(true);//设置带有删除线效果

模糊

image.png
image.png
image.png
image.png
setLayerType(LAYER_TYPE_SOFTWARE,null)
p.setMaskFilter(BlurMaskFilter(5f,BlurMaskFilter.Blur.SOLID))


    public enum Blur {
        /**
         * Blur inside and outside the original border.
         */
        NORMAL(0),

        /**
         * Draw solid inside the border, blur outside.
         */
        SOLID(1),

        /**
         * Draw nothing inside the border, blur outside.
         */
        OUTER(2),

        /**
         * Blur inside the border, draw nothing outside.
         */
        INNER(3);
    }

bitmap有个方法如下,可以获取一个新的bitmap,只包含透明度,没有色值,或者说返回的图片就是黑色的,带透明度的,
如下图,左侧是原图,浅蓝色外圈中间是白色的, 右边的是只有透明度的图


image.png
    /**
     * Returns a new bitmap that captures the alpha values of the original.
     * This may be drawn with Canvas.drawBitmap(), where the color(s) will be
     * taken from the paint that is passed to the draw call.
     *
     * @return new bitmap containing the alpha channel of the original bitmap.
     */
    @CheckResult
    public Bitmap extractAlpha() {
        return extractAlpha(null, null);
    }

上边说道了blur,可以模糊画笔,那么对这种图片的影响是啥,可以看下效果,染成红色


image.png
        val bpExtra = bp!!.extractAlpha()//或者bp!!.extractAlpha(Color.RED,null),后边canvas draw的时候就不需要paint了
        p.color = Color.RED
        p.setMaskFilter(BlurMaskFilter(5f, BlurMaskFilter.Blur.OUTER))
        canvas.drawBitmap(bpExtra, 10f, 10f, p)

Shader

Shader is the based class for objects that return horizontal spans of colors during drawing. A subclass of Shader is installed in a Paint calling paint.setShader(shader). After that any object (other than a bitmap) that is drawn with that paint will get its color(s) from the shader


image.png
image.png

BitmapShader

给paint设置了这个shader以后,那么就相当于画布从0,0开始到bitmap的宽,高范围里,paint的色值已经确定了。
这时候如果你canvas.drawCircle,那么就会看到这个圆圈里就是图片的一部分,好像望远镜一样

public BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)

LinearGradient

线性的着色器,就是创建一个沿着直线绘制线性渐变的着色器。
x0,y0,起始位置,x1,y1终点位置,然后颜色值,位置数组【取值范围0到1】,长度和颜色值一样,或者为空也可以。最后就是扩展模式了。上边有讲过

public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[],
            @Nullable float positions[], @NonNull TileMode tile)

//上边构造方法的简化版,
public LinearGradient(float x0, float y0, float x1, float y1,
            @ColorInt int color0, @ColorInt int color1,
            @NonNull TileMode tile)

实现文在渐变动画也比较简单
我们在一个线条范围内设置个色值变化,完事设置个TileMode,那么其实整个画布范围内的颜色就已经确定了
比如我们设置repeat模式,完事色值从红到蓝,范围从0到100,那么100到200也是红到蓝,200到300也是

linearGradient=LinearGradient(100f-bounds.width(),0f,100f,0f, intArrayOf(Color.RED,Color.BLUE), floatArrayOf(0f,1f),Shader.TileMode.MIRROR)

 val mt=Matrix()
      mt.setTranslate(transX.toFloat(),0f)//对x轴方向进行平移,比如移动了10,那么就相当于10到110是红蓝,-90到10是红蓝。
        linearGradient?.setLocalMatrix(mt)
        p.setShader(linearGradient)
 canvas.drawText(text,0,text.length,100f,100f,p)

RadialGradient

从内向外发射的一个着色器,构造方法和线性的差不多,不过这种是从圆心向外部扩散,就和波纹一样
参数,中心原点,半径,颜色,完事根据重复的模式TileMode,也能知道半径以外的色值了,也就是整个画布的颜色都确定拉。

public RadialGradient(float centerX, float centerY, float radius,
            @NonNull @ColorInt int colors[], @Nullable float stops[],
            @NonNull TileMode tileMode)
public RadialGradient(float centerX, float centerY, float radius,
            @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode)
image.png

代码如下

        p.shader=RadialGradient(100f,100f,50f,Color.RED,Color.BLUE,Shader.TileMode.REPEAT)
        canvas.drawCircle(100f,100f,80f,p)
        canvas.drawCircle(300f,150f,100f,p)
        p.shader=null

SweepGradient

类似雷达扫描那种,给个中心点,给几个色值即可


image.png
public SweepGradient(float cx, float cy,
            @NonNull @ColorInt int colors[], @Nullable float positions[])
public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1)

ComposeShader

这种没太弄懂,就是2种shader根据PorterDuff.Mode进行重组,可是以我的理解,每种shader好像大小都是无限的也就是和画布大小一样,那么这个Mode感觉是无用的啊,最终还是用的shaderA

public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB,
            @NonNull PorterDuff.Mode mode)

canvas.drawBitmapMesh

这个方法可以对图片进行一些处理,比较扭曲,拉伸等,就是把图片分成多个网格,然后操作顶点的位置
bitmap:一张图
meshWidth:横向分成多少份
meshHeight:纵向分成多少份
verts:所有顶点的坐标,依次是x,y,也就是偶数索引存储x,奇数索引存储y值,数组最小值为
(meshWidth+1) * (meshHeight+1) * 2 + vertOffset
vertOffset: verts数组跳过多少条数据
colors:最小长度(meshWidth+1) * (meshHeight+1) + colorOffset,可以为空,弄个颜色,大家一起来染色
colorOffset:同vertOffset,相对colors来说的

public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight,
            @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset,
            @Nullable Paint paint) 

关键还是对verts里的坐标进行处理。其他都不是重点。

相关文章

网友评论

      本文标题:view基础学习

      本文链接:https://www.haomeiwen.com/subject/akgllqtx.html