Android 绘制字符串到自定义view的中心

处理字符串的长度和宽度,并没有想象中的那么简单,要讲字符串画到自定义view的中心点,更加没有那么简单!

1. 计算字符串的长度

介绍两种计算方法,但是结果却很意外哦!

(1)最小外接矩形


paint.setTextSize(textSize);paint.setTypeface(Typeface.MONOSPACE);Rect r = new Rect();paint.getTextBounds(text,0,text.length(),r);int height = r.bottom - r.top;int width = r.right - r.left;

(2)使用FontMetrics

Paint.FontMetrics fm = paint.getFontMetrics();
float textWidth = paint.measureText(text);
float textHeight = fm.bottom - fm.top;

说明:这两种方法计算方法结果会有很大的出入,原因是什么呢?据我猜测啊...第一种方法是计算字符串所占的最小大小,也就是包围字符串的最小外接矩形(可以算出字符串的实际长度和宽度);而第二种则是老外针对他们的字母的计算,看看字母a,b,j这些要怎么计算它的高度?难道a,b,j都要有一个计算其高度的算法?不可能啊,显示出来也不美观,最起码得按字母j计算,补上a和b缺少的部分,让所有的字母都是一个高度,老外就想了个辙,把字母的整个高度分成好几个部分(想想小学写拼音的),你想要什么自己处理去,比如:descent,ascent,top,bottom以及leading,这些东西都封装在FontMetrics类里面。下面是两种种算法的示意图。

2. 自定义view

自定义一个圆圈

Circle View {

    private String text            = "帅";
    private int textColor          = Color.BLACK;
    private int textSize           = 0;
    private PointF center          = new PointF(0.0f, 0.0f);
    private float strokeWidth      = 0.0f;
    private float radius           = 0.0f;
    private int fillColor          = Color.RED;
    private int strokeColor        = Color.GREEN;

    private Paint paint;

    public Circle(Context context) {
        (context, );
    }

    public Circle(Context context, AttributeSet attrs) {
        (context, attrs, );
    }

    public Circle(Context context, AttributeSet attrs, defStyleAttr) {
        (context, attrs, defStyleAttr);
        TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.);
        count = ta.getIndexCount();
        for(int i=0; i<count; i++) {
            int attr = ta.getIndex(i);
            switch(attr) {
                case R.styleable.Circle_text:
                    text = ta.getString(attr);
                    break;
                case R.styleable.Circle_textSize:
                    textSize = (int)ta.getDimension(attr,0.0f);
                    break;
                case R.styleable.Circle_textColor:
                    textColor = ta.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.Circle_radius:
                    radius = ta.getDimension(attr, 0.0f);
                    break;
                case R.styleable.Circle_strokeWidth:
                    strokeWidth = ta.getDimension(attr, 0.0f);
                    break;
                case R.styleable.Circle_fillColor:
                    fillColor = ta.getColor(attr, Color.RED);
                    break;
                case R.styleable.Circle_strokeColor:
                    strokeColor = ta.getColor(attr, 0);
                    break;
                default:
                    break;
            }
        }
        ta.recycle();

        init(context);
    }

    private void init(Context context) {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if(radius <= 0) {
            return;
        }
    
        float cx = center.x + radius;
        float cy = center.y + radius;
        //fill
        paint.setColor(fillColor);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(cx, cy, radius, paint);
        //text
        if(!text.isEmpty()&& textSize>0) {
            paint.setColor(textColor);
            paint.setTextSize(textSize);
            paint.setTypeface(Typeface.MONOSPACE);
            Rect r = new Rect();
            paint.getTextBounds(text,0,text.length(),r);
            int height = r.bottom - r.top;
            int width = r.right - r.left;
            Paint.FontMetrics fm = paint.getFontMetrics();
            float textWidth = paint.measureText(text);
            float textHeight = fm.bottom - fm.top;
            float offsetX = width / 2;
            float offsetY = height/2 - (fm.bottom - (textHeight - height)/2);
            canvas.drawText(text, cx-offsetX, cx+offsetY, paint);
        }
        //stroke
        if(strokeWidth > 0) {
            paint.setColor(strokeColor);
            paint.setStrokeWidth(strokeWidth);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawCircle(cx, cy, radius, paint);
        }
    }

上面只是部分代码,看看onDraw方法就可以了。可见我上面画了一个圆圈并描边了,并且在圆圈里面画了一个字符串,让字中心居于圆心。在让字居于圆心,可是走了一段路,请看下面图解(看看上面代码offsetY的得到)。

从上图可以清晰的看出,y方向应该偏移的量:offsetY = h2/2-(bh-(h1-h2)/2)。

3. 效果

时间: 2025-01-06 06:47:02

Android 绘制字符串到自定义view的中心的相关文章

Android知识梳理之自定义View

虽然android本身给我们提供了形形色色的控件,基本能够满足日常开发的需求,但是面对日益同质化的app界面,和不同的业务需求.我们可能就需要自定义一些View来获得比较好的效果.自定义View是android开发者走向高级开发工程师必须要走的一关. 转载请标明出处:http://blog.csdn.net/unreliable_narrator/article/details/51274264 一,构造函数: 当我们创建一个类去继承View的时候,会要求我们至少去实现一个构造函数. publi

【Android 应用开发】 自定义 View 组件 -- 圆形进度条

转载著名出处 : http://blog.csdn.net/shulianghan/article/details/40351487 代码下载 : -- CSDN 下载地址 : http://download.csdn.net/detail/han1202012/8069497 ; -- GitHub 地址 : https://github.com/han1202012/CircleProcess.git ; -- 工程示例 : 一. 相关知识点解析 1. 自定义 View 组件构造方法 构造方

Android 如何 画 柱状图 -------自定义View

实现了 柱状图 根据 SeekBar的滑动 改变的效果: 图示效果: 自定义View的代码: package com.example.coustomviewdemo; import android.R.color; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.g

Android属性动画与自定义View——实现vivo x6更新系统的动画效果

晚上好,现在是凌晨两点半,然后我还在写代码.电脑里播放着<凌晨两点半>,晚上写代码,脑子更清醒,思路更清晰. 今天聊聊属性动画和自定义View搭配使用,前面都讲到自定义View和属性动画,但是一起用的还是不多,刚巧今晚手机提示我更新系统,我看到那个更新的动画还不错,仔细的分析了一下,于是我也决定写一个,不是一模一样的,但是效果和原理是一样的. 先看看图: 这是一张静态的图,这里有三个波浪线,当下载完之后,波浪线会往上活动,一直到消失. 所以难点也是在这个波浪线上.这个波浪线类似于一个水波纹,也

Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)

转载请注明地址:http://blog.csdn.net/xiaanming/article/details/10298163 很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View

Android ——利用OnDraw实现自定义View(转)

自定义View的实现方式大概可以分为三种,自绘控件.组合控件.以及继承控件.本文将介绍自绘控件的用法.自绘控件的意思是,这个控件上的内容是用onDraw函数绘制出来的.关于onDraw函数的介绍可参看 Android视图绘制流程完全解析,带你一步步深入了解View(二) . 例子1:在layout文件中使用自绘控件 出处:http://blog.csdn.net/guolin_blog/article/details/17357967 下面我们准备来自定义一个计数器View,这个View可以响应

Android应用开发之自定义View触摸相关工具类全解

背景 最近有些乱,各种事情,各种交叉.好在还有一点上进心,于是继续将自定义这个系列的核心知识再梳理一下吧.关于自定义控件前面博文说过了,这里不会教你拿来主义,只授之以渔,如果你喜欢拿来主义,不好意思,请绕行,如果你喜欢得渔,那请继续. 前面我们已经叙述过了几篇关于自定义View涉及的东西,大家可以自己回过头去看我之前的博客,譬如事件处理.坐标系.工具类等.下面我们还是继续补充一些常用的自定义控件工具类. [工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请

Android Matrix手势缩放自定义view 不止于Imageview

转载请注明出处:http://blog.csdn.net/coderyue/article/details/51397409 之前写过一篇文章Android TextView 横竖排切换(字方向不变) 是自定义了一个LinearLayout, 实现了当然还不够, 还要对它进行操作, 平移,旋转 and 缩放, 相信很多小伙伴都知道对图片的平移等等操作最好用的就是矩阵了,因为有个方法叫做imageview.setImageMatrix(matrix), 直接构造一个矩阵对象然后设置到图片上就进行相

Android 用属性动画自定义view的渐变背景

自定义view渐变背景,同时监听手势自动生成小圆球. 宿主Activity如下: package com.edaixi.tempbak; import java.util.ArrayList; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ArgbE