上次去一个公司面试,面试官问了一个题,怎么用android的自定义view实现一个公章的效果,据说这是华为之前的面试题,我想了下,要是公章的效果,最外层是一个圆,里面是一个五角星,但是这文字怎么画呢,比较难搞,后来回来看了下java的api,发现人家的Path里面本来就提供了这么一个方法:

public void addArc(RectF oval, float startAngle, float sweepAngle) {
    addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
}

然后人家解释说了,根据狐线的角度生成相应的路径,所以我们就可以给文字设置一个相应绘制区域,使其绘制的文字都在这个区域内,

path.addArc(oval,-(firstrad-), textPadding);
接下来我们只需要在这个区域内把文字绘制上去就行了。
好的,下面是全部代码:

首先继承自View,我们在构造里面初始化,同样为了方便程序的扩展性,我们用自定义属性,
<declare-styleable name="Seal">
    <attr name="scale_text_size" format="dimension" />
    <attr name="scale_text_color" format="color" />
    <attr name="scale_text" format="string" />
    <attr name="scale_text_padding" format="float" />
    <attr name="circle_stroke_width" format="dimension" />
    <attr name="circle_color" format="color" />
    <attr name="circle_radius" format="dimension" />
</declare-styleable>

然后我们初始化的时候主要初始化文字,文字大小,文字间距,文字颜色等等,
private void initViews(AttributeSet attrs, int defStyle) {
    TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.Seal, defStyle, 0);
    circleText = typedArray.getString(R.styleable.Seal_scale_text);
    textSize = typedArray.getDimension(R.styleable.Seal_scale_text_size, 20);
    scaleTextColor = typedArray.getColor(R.styleable.Seal_scale_text_color, getResources().getColor(R.color.c9));
    textPadding=typedArray.getFloat(R.styleable.Seal_scale_text_padding,50);
    circleStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.Seal_circle_stroke_width, 3);
    circleColor = typedArray.getColor(R.styleable.Seal_circle_color, getResources().getColor(R.color.c9));
    circleRadius = typedArray.getDimensionPixelSize(R.styleable.Seal_circle_radius, 7);
    typedArray.recycle();
}

接下来我们在重写Ondraww(Canvas canvas)

@Override
protected void onDraw(Canvas rootCanvas) {
    super.onDraw(rootCanvas);
    Bitmap image = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(image);
    Paint paint=new Paint();

    drawRing(canvas,paint);
    drawStar(canvas);
    drawText(canvas);
    rootCanvas.drawBitmap(image, 0, 0, null);
}

接下来是对应的三个方法:画圆环(ring),五角星(star),文字(text)
//圆环
private void drawRing(Canvas canvas, Paint paint) {
    centre = canvas.getWidth() / 2; // 获取圆心的x坐标
    radius = (int) (centre - circleStrokeWidth / 2); // 圆环的半径
    paint.setColor(Color.RED); // 设置圆环的颜色
    paint.setStyle(Paint.Style.STROKE); // 设置空心
    paint.setStrokeWidth(circleStrokeWidth); // 设置圆环的宽度
    paint.setAntiAlias(true); // 消除锯齿
    canvas.drawCircle(centre, centre, radius, paint); // 画出圆环
}

//绘制五角星

private void drawStar(Canvas canvas){
    float start_radius = (float) ((radius / 2)*1.1);
    int x = centre, y = centre;
    float x1,y1,x2,y2,x3,y3,x4,y4,x5,y5;
    float r72 = (float) Math.toRadians(72);
    float r36 = (float) Math.toRadians(36);
    //顶点
    x1 = x;
    y1 = y - start_radius;
    //左1
    x2 = (float) (x - start_radius*Math.sin(r72));
    y2 = (float) (y - start_radius*Math.cos(r72));
    //右1
    x3 = (float) (x + start_radius*Math.sin(r72));
    y3 = (float) (y - start_radius*Math.cos(r72));
    //左2
    x4 = (float) (x - start_radius*Math.sin(r36));
    y4 = (float) (y + start_radius*Math.cos(r36));
    //右2
    x5 = (float) (x + start_radius*Math.sin(r36));
    y5 = (float) (y + start_radius*Math.cos(r36));

    //连接各个节点,绘制五角星
    Path path = new Path();
    path.moveTo(x1, y1);
    path.lineTo(x5, y5);
    path.lineTo(x2, y2);
    path.lineTo(x3, y3);
    path.lineTo(x4, y4);
    path.close();

    Paint paint = new Paint();
    paint.setColor(Color.RED);

    canvas.drawPath(path, paint);
}

//文字

private void drawText(Canvas canvas){
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    paint.setTypeface(Typeface.DEFAULT_BOLD);
    paint.setTextAlign(Paint.Align.CENTER);
    paint.setTextSize(radius/5+5);
    //圆弧文字所在矩形范围
    RectF oval=new RectF(0, 0, 2*radius, (float) (2*radius));
    //第一个文字偏移角度,其中padding/2为文字间距
    float firstrad = 90 + textPadding * (circleText.length()) / 4 - textPadding/8;
    for(int i = 0; i < circleText.length(); i++){
        Path path = new Path();
        //根据角度生成弧线路径
        path.addArc(oval,-(firstrad-textPadding*i/2), textPadding);
        canvas.drawTextOnPath(String.valueOf(circleText.charAt(i)), path, -(float) (radius/3),(float) (radius/3), paint);
    }
}

最后在我们需要的视图中引用下就好了

<com.xzh.sealmaster.view.SealView
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:layout_gravity="center"
    app:scale_text_size="16sp"
    app:scale_text_padding="50"
    app:scale_text="华为上海有限公司"
    />

有需要源码的,请到下面地址下载:http://download.csdn.net/detail/xiangzhihong8/9479372

好的,就是这么简单,有任何疑问的请加我们的技术群278792776或者188716429

android自定义view实现公章效果的更多相关文章

  1. Android 自定义View跑马灯效果(一)

    今天通过书籍重新复习了一遍自定义VIew,为了加强自己的学习,我把它写在博客里面,有兴趣的可以看一下,相互学习共同进步: 通过自定义一个跑马灯效果,来诠释一下简单的效果: 一.创建一个类继承View, ...

  2. android 自定义view之侧滑效果

    效果图: 看网上的都是两个view拼接,默认右侧的不显示,水平移动的时候把右侧的view显示出来.但是看最新版QQ上的效果不是这样的,但给人的感觉却很好,所以献丑来一发比较高仿的. 知识点: 1.Vi ...

  3. Android自定义View 画弧形,文字,并增加动画效果

    一个简单的Android自定义View的demo,画弧形,文字,开启一个多线程更新ui界面,在子线程更新ui是不允许的,但是View提供了方法,让我们来了解下吧. 1.封装一个抽象的View类   B ...

  4. Android自定义View(LimitScrollerView-仿天猫广告栏上下滚动效果)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/53303872 本文出自:[openXu的博客] 1分析 2定义组合控件布局 3继承最外层控件 ...

  5. Android 自定义View合集

    自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...

  6. Android 自定义 view(三)—— onDraw 方法理解

    前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...

  7. Android 自定义view(二) —— attr 使用

    前言: attr 在前一篇文章<Android 自定义view -- attr理解>已经简单的进行了介绍和创建,那么这篇文章就来一步步说说attr的简单使用吧 自定义view简单实现步骤 ...

  8. Android 自定义View及其在布局文件中的使用示例(二)

    转载请注明出处 http://www.cnblogs.com/crashmaker/p/3530213.html From crash_coder linguowu linguowu0622@gami ...

  9. Android自定义View

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24252901 很多的Android入门程序猿来说对于Android自定义View ...

随机推荐

  1. MySQL 存储过程探秘

    关于存储过程的优点,本文不再阐述.这里只是对创建存储过程时可能遇到的问题做一下简单的分析. 必备基础 这里说的基础,是相关于如何创建一个存储过程的. DELIMITER:分隔符,定界符. 作用就是:作 ...

  2. Spark集群术语

    Spark集群术语解析 1. Application Application是用户在Spark上构建(编写)的程序,包含driver program 和executors(分布在集群中多个节点上运行的 ...

  3. Java项目源码为什么要做代码混淆(解释的很好)

    代码混淆,是将计算机程序的代码转换成一种功能上等价,但是难于阅读和理解的形式的行为.代码混淆可以用于程序源代码,也可以用于程序编译而成的中间代码.执行代码混淆的程序被称作代码混淆器.目前已经存在许多种 ...

  4. 利用gradle添加构建版本号

    在java的程序中,貌似都没有这个构建版本号的概念,用的诸如eclipse, idea和android studio的IDE也没有直接提供构建版本号的选项.不过我却想在android程序的版本号当中添 ...

  5. iOS中 Swift初级入门学习(二)

    // Copyright (c) 2015年 韩俊强. All rights reserved. // import Foundation /* // 控制语句 // for - in // 遍历字符 ...

  6. 基于java自身技术实现消息方式的系统间通信

    这篇博客基本照搬了分布式java应用基础与实践一书的内容 java自带的远程调用分两种一种是rmi,一种是webservice 我们先看rmi(remote method invoke)# 使用rmi ...

  7. JAVA DOM4j解析XML数据到自定义javabean

    我们获取xml中的数据,一般以面向对象的思想去处理这些数据.因此,我们需要自定义类来封装解析出来的数据,以方便我们操作这些数据. 自定义的java类,称为javabean. 自定义Contact类代码 ...

  8. tomcat的realm域

    Realm域,其实可以看成是一个包含了用户及密码的数据库,而且每个用户还会包含了若干角色.也就是包含了用户名.密码.角色三个列的数据记录集合,如下图,最下面椭圆内的包含的整块即可以看成realm域.它 ...

  9. Java Swing 之Timer配合JProgressBar的使用

    Timer作为java开发中常用的一个定时工具,配合JProgressBar使用起来还真是方便,只需要调用timer.start()方法就能激活并运行,然后调用stop()方法便能停止,还可以再次通过 ...

  10. 《java入门第一季》正则表达式小案例

    案例一:当你登陆某个论坛,向发帖子留下自己qq号的时候,可惜你的号码就是留不下,总是输入*,或者其它奇妙的字符串.其实原理就是用了正则表达式替换. /* * 替换功能 * String类的public ...