Android 自定义UI--指南针
有了之前的基础,下面开始实现一个简单的指南针。首先来看一下效果图,
我们可以粗略将这个指南针分为三个部分,一是圆形背景,二是刻度,三是文本。那么在写代码的时候,就可以声明三个Paint画笔来画以上三个物体。代码如下:
- package com.example.apptest;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.View;
- /**
- * 指南针
- *
- */
- class CompassView extends View {
- //刻度画笔
- private Paint markerPaint;
- //文本画笔
- private Paint textPaint;
- //圆形画笔
- private Paint circlePaint;
- //字符串
- private String northString;
- //字符串
- private String eastString;
- //字符串
- private String southString;
- //字符串
- private String westString;
- //文本高度
- private int textHeight;
- //轴
- private float bearing;
- /**
- *
- * @param _bearing
- */
- public void setBearing(float _bearing) {
- bearing = _bearing;
- }
- /**
- *
- * @return
- */
- public float getBearing() {
- return bearing;
- }
- public CompassView(Context context) {
- super(context);
- initCompassView();
- }
- public CompassView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initCompassView();
- }
- public CompassView(Context context, AttributeSet attrs, int defaultStyle) {
- super(context, attrs, defaultStyle);
- initCompassView();
- }
- protected void initCompassView() {
- setFocusable(true);
- // 东西南北
- northString = "北";
- eastString = "东";
- southString = "南";
- westString = "西";
- // 设置实心圆画笔
- circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- circlePaint.setColor(Color.BLACK);
- circlePaint.setStrokeWidth(1);
- circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
- // 设置线条画笔 刻度
- markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- markerPaint.setColor(Color.RED);
- // 设置坐标画笔 东西南北 度数
- textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- textPaint.setColor(Color.WHITE);
- // 设置文字高度
- textHeight = (int) textPaint.measureText("yY");
- Log.i("textHeight", textHeight+"");
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int measuredWidth = measure(widthMeasureSpec);
- int measuredHeight = measure(heightMeasureSpec);
- int d = Math.min(measuredWidth, measuredHeight);
- setMeasuredDimension(d, d);
- }
- /**
- * @category
- * @param measureSpec
- * @return
- */
- private int measure(int measureSpec) {
- int result = 0;
- int specMode = MeasureSpec.getMode(measureSpec);
- int specSize = MeasureSpec.getSize(measureSpec);
- if (specMode == MeasureSpec.UNSPECIFIED) {
- result = 200;
- } else {
- result = specSize;
- }
- return result;
- }
- @Override
- protected void onDraw(Canvas canvas) {
- // 圆心坐标
- int px = getMeasuredWidth() / 2;
- Log.i("px", px+"");
- int py = getMeasuredHeight() / 2;
- Log.i("py", py+"");
- // 半径 取最小值
- int radius = Math.min(px, py);
- Log.i("radius", radius+"");
- // 画圆
- canvas.drawCircle(px, py, radius, circlePaint);
- canvas.save();
- canvas.rotate(-bearing, px, py);
- // 东西南北 坐标位置
- int textWidth = (int) textPaint.measureText("W");
- Log.i("textWidth", textWidth+"");
- int cardinalX = px - textWidth / 2;
- Log.i("cardinalX", cardinalX+"");
- int cardinalY = py - radius + textHeight;
- Log.i("cardinalY", cardinalY+"");
- //画24个刻度
- for (int i = 0; i < 24; i++) {
- //画刻度
- canvas.drawLine(px, py - radius, px, py - radius + 10, markerPaint);
- canvas.save();
- //移动原点textHeight距离 开始画东西南北以及度数
- canvas.translate(0, textHeight);
- //判断如果满足条件画东西南北
- if (i % 6 == 0) {
- String dirString = "";
- switch (i) {
- case (0): {
- dirString = northString;
- // 画指南针
- int arrowY = 2 * textHeight;
- canvas.drawLine(px, arrowY, px - 5, 3 * textHeight,
- markerPaint);
- canvas.drawLine(px, arrowY, px + 5, 3 * textHeight,
- markerPaint);
- break;
- }
- case (6):
- dirString = eastString;
- break;
- case (12):
- dirString = southString;
- break;
- case (18):
- dirString = westString;
- break;
- }
- //画东西南北
- canvas.drawText(dirString, cardinalX, cardinalY, textPaint);
- }else if (i % 3 == 0) {//判断如果满足条件画4个度数
- String angle = String.valueOf(i * 15);
- float angleTextWidth = textPaint.measureText(angle);
- int angleTextX = (int) (px - angleTextWidth / 2);
- int angleTextY = py - radius + textHeight;
- //画弧度数
- canvas.drawText(angle, angleTextX, angleTextY, textPaint);
- }
- canvas.restore();
- //每隔15度旋转一下
- canvas.rotate(15, px, py);
- }
- canvas.restore();
- }
- }
这个例子中,多了一个measure过程,重写了OnMeasure()过程,用于计算View的大小。先不细说这个,下面重点说一下如何画图的。背景很简单,不多说,难点还是在于刻度以及文字的实现。我们知道,画文本可以使用drawText()方法,画刻度也就是画直线,可以使用drawLine()方法。那关键问题就是在哪个位置画刻度以及文本。本例子中,圆形的大小取决于屏幕的宽度,可以看到圆形的直接就是屏幕的宽度。画刻度线也是从圆心坐标开始的,直接使用drawLine()方法。还有一个地方需要注意就是东西南北以及刻度的文字是移动了一段距离后开始绘制的,使用的方法就是translate(),在画完14个刻度之后调用这个方法。
Android 自定义UI--指南针的更多相关文章
- android自定义UI模板图文详解
不知道大家在实际开发中有没有自定义过UI模板?今天花时间研究了一下android中自定义UI模板,与大家分享一下. 每个设计良好的App都是自定义标题栏,在自定义标题栏的过程中大部分人可能都是自定义一 ...
- Android自定义UI的实现和应用
在Android项目开发中,不可避免的要遇到自定义的UI,用较好的体验去讨好UED妹子和交互设计师手下留情~几个迭代下来,遇到了不少这样的要求,有简单有复杂.最好的实现方案就是讲业务和UI隔离,封装成 ...
- Android自定义UI模板
第一步:自定义xml属性 新建一个android项目,在values文件夹中新建一个atts.xml的文件,在这个xml文件中声明我们一会在使用自定义控件时候需要指明的属性.atts.xml < ...
- android自定义View之NotePad出鞘记
现在我们的手机上基本都会有一个记事本,用起来倒也还算方便,记事本这种东东,如果我想要自己实现,该怎么做呢?今天我们就通过自定义View的方式来自定义一个记事本.OK,废话不多说,先来看看效果图. 整个 ...
- Android开源的精美日历控件,热插拔设计的万能自定义UI
Android开源的精美日历控件,热插拔设计的万能自定义UI UI框架应该逻辑与界面实现分离,该日历控件使用了热插拔的设计 ,简单几步即可实现你需要的UI效果,热插拔的思想是你提供你的实现,我提供我的 ...
- Android自定义View和控件之一-定制属于自己的UI
照例,拿来主义.我的学习是基于下面的三篇blog.前两是基本的流程,第三篇里有比较细致的绘制相关的属性.第4篇介绍了如何减少布局层次来提高效率. 1. 教你搞定Android自定义View 2. 教你 ...
- Android自定义View 画弧形,文字,并增加动画效果
一个简单的Android自定义View的demo,画弧形,文字,开启一个多线程更新ui界面,在子线程更新ui是不允许的,但是View提供了方法,让我们来了解下吧. 1.封装一个抽象的View类 B ...
- Android 自定义View合集
自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...
- Android 自定义View (五)——实践
前言: 前面已经介绍了<Android 自定义 view(四)-- onMeasure 方法理解>,那么这次我们就来小实践下吧 任务: 公司现有两个任务需要我完成 (1)监测液化天然气液压 ...
- [原] Android 自定义View步骤
例子如下:Android 自定义View 密码框 例子 1 良好的自定义View 易用,标准,开放. 一个设计良好的自定义view和其他设计良好的类很像.封装了某个具有易用性接口的功能组合,这些功能能 ...
随机推荐
- C#去除byte数组头尾杂质(即不需要的数据)
代码如下: /// <summary> /// 去除byte数组头尾杂质(即不需要的数据) /// </summary> /// <param name="ar ...
- [编译原理代码][NFA转DFA并最小化DFA并使用DFA进行词法分析]
#include <iostream> #include <vector> #include <cstring> #include "stack" ...
- canvas-画蜗牛
<!doctype html><html lang="en"> <head> <meta charset="UTF-8" ...
- UIViewController的生命周期(图解)
当一个视图控制器被创建,并在屏幕上显示的时候. 代码的执行顺序1. alloc 创建对象,分配空间2.init (initWithNibName ...
- 打开较大存储量的.sql文件时,出现SQL Server 阻止了对组件 'xp_cmdshell' 的 过程'sys.xp_cmdshell' 的访问
1. “消息 15281,级别 16,状态 1,过程 xp_cmdshell,第 1 行SQL Server 阻止了对组件 'xp_cmdshell' 的 过程'sys.xp_cmdshell' 的访 ...
- hihoCoder挑战赛14 A,B,C题解
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud 题目1 : 不等式 时间限制:10000ms 单点时限:1000ms 内存限制:2 ...
- 转自:Tsihang 三层网络设备对于IP报文的分片和重组处理原理
三层网络设备对于IP报文的分片和重组处理原理 对于网络分片,我一年前就想整理出来,虽然说网络上的资料很多,但是真正掌握精髓的除非真正做过分片程序,不然很难将协议栈整体联系起来理解.这篇文章,包括设计分 ...
- sql server在使用xp_cmdshell
一.sql server在使用xp_cmdshell读取远程服务器上的文件时,要先将远程服务器的目录映射到本地 代码: exec master..xp_cmdshell 'net use P: \\ ...
- css应用三
1. Padding与margin Padding为内边距,padding值会计算在width和height之内.如:width:100px:height:100px:padding:10px:该di ...
- GO语言练习ONE