在接下来的例子里,你将通过扩展View类创建一个指南针View。它使用传统的指南针上升箭头来指示方向。当完成时,应该和图4-3看起来一样。

指南针是一个UI控件的例子,它需要完全不同的视觉显示,不同于SDK工具箱中的TextView和Button,让我们从无到有使它成为一个出色的控件。

在第10章,你将使用这个指南针View和设备内建的重力加速计来显示用户当前的方向。在11章中,你将学习更高级的Canvas绘制技巧来戏剧性地改进它的外观。

图4-3

1. 创建一个新的指南针工程,包含指南针View和拥有它的Activity。现在创建CompassView类来扩展View。创建构造函数来运行View可以在代码中实例化,或者通过资源layout的膨胀。添加一个新的initCompassView方法来初始化控件,并在每个构造函数中调用它。

package com.paad.compass;

import android.content.Context;

import android.graphics.*;

import android.graphics.drawable.*;

import android.view.*;

import android.util.AttributeSet;

import android.content.res.Resources;

public class CompassView extends View {

public CompassView(Context context) {

super(context);

initCompassView();

}

public CompassView(Context context, AttributeSet attrs) {

super(context, attrs);

initCompassView();

}

public CompassView(Context context, AttributeSet ats, int defaultStyle) {

super(context, ats, defaultStyle);

initCompassView();

}

protected void initCompassView() {

setFocusable(true);

}

}

2. 指南针控件应该总是一个圆的方式占据画布允许的尽可能多的空间。重写onMeasure方法来计算最小的边,使用setMeasuredDimension来设置高度和高度值。

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// The compass is a circle that fills as much space as possible.

// Set the measured dimensions by figuring out the shortest boundary,

// height or width.

int measuredWidth = measure(widthMeasureSpec);

int measuredHeight = measure(heightMeasureSpec);

int d = Math.min(measuredWidth, measuredHeight);

setMeasuredDimension(d, d);

}

private int measure(int measureSpec) {

int result = 0;

// Decode the measurement specifications.

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

if (specMode == MeasureSpec.UNSPECIFIED)

{

// Return a default size of 200 if no bounds are specified.

result = 200;

}

else

{

// As you want to fill the available space

// always return the full available bounds.

result = specSize;

}

return result;

}

3. 创建两个你将在绘制指南针时用到的资源文件:颜色和字符串。

3.1. 创建文本字符串资源 /res/values/strings.xml.

<?xml version=”1.0” encoding=”utf-8”?>

<resources>

<string name=”app_name”>Compass</string>

<string name=”cardinal_north”>N</string>

<string name=”cardinal_east”>E</string>

<string name=”cardinal_south”>S</string>

<string name=”cardinal_west”>W</string>

</resources>

3.2. 创建颜色资源 /res/values/colors.xml.

<?xml version=”1.0” encoding=”utf-8”?>

<resources>

<color name=”background_color”>#F555</color>

<color name=”marker_color”>#AFFF</color>

<color name=”text_color”>#AFFF</color>

</resources>

4. 现在回到CompassView类中。创建一个用来显示方向的属性并为它创建get和set方法。

private float bearing;

public void setBearing(float _bearing) {

bearing = _bearing;

}

public float getBearing() {

return bearing;

}

5. 接下来,返回到initCompassView方法中,获取第3步中创建的资源的引用。以类作用域的方法存储字符串值和由颜色值创建的Paint对象。你将在下一步中用这些对象来绘制指南针。

private Paint markerPaint;

private Paint textPaint;

private Paint circlePaint;

private String northString;

private String eastString;

private String southString;

private String westString;

private int textHeight;

protected void initCompassView() {

setFocusable(true);

circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

circlePaint.setColor(R.color. background_color);

circlePaint.setStrokeWidth(1);

circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);

Resources r = this.getResources();

northString = r.getString(R.string.cardinal_north);

eastString = r.getString(R.string.cardinal_east);

southString = r.getString(R.string.cardinal_south);

westString = r.getString(R.string.cardinal_west);

textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

textPaint.setColor(r.getColor(R.color.text_color));

textHeight = (int)textPaint.measureText(“yY”);

markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

markerPaint.setColor(r.getColor(R.color.marker_color));

}

6. 最后一步就是用第5步中创建的字符串和Paint对象来绘制指南针。接下来的代码片段只给出了有限的提示。你可以在第11章找到更多关于如何在Canvas上绘制和使用高级的Paint效果的细节。

6.1. 首先重写onDraw方法。

@Override

protected void onDraw(Canvas canvas) {

6.2. 找到控件的中心,存储最小边的长度作为指南针的半径。

int px = getMeasuredWidth() / 2;

int py = getMeasuredHeight() /2 ;

int radius = Math.min(px, py);

6.3.  使用drawCircle方法绘制外边框,背景的颜色使用第5步中创建的circlePaint对象。

// Draw the background

canvas.drawCircle(px, py, radius, circlePaint);

6.4. 指南针通过旋转面板来显示当前的指向,所以当前的方向总是在设备的顶端。为了达到这个效果,沿着当前指向的相反方向来旋转画布。

// Rotate our perspective so that the ‘top’ is

// facing the current bearing.

canvas.save();

canvas.rotate(-bearing, px, py);

6.5. 现在剩下来的就是绘制表盘。旋转画布一周,每隔15°绘制一个标记,每隔45°绘制一个方向字符串。

int textWidth = (int)textPaint.measureText(“W”);

int cardinalX = px-textWidth/2;

int cardinalY = py-radius+textHeight;

// Draw the marker every 15 degrees and text every 45.

for (int i = 0; i < 24; i++)

{

// Draw a marker.

canvas.drawLine(px, py-radius, px, py-radius+10, markerPaint);

canvas.save();

canvas.translate(0, textHeight);

// Draw the cardinal points

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)

{

// Draw the text every alternate 45deg

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();

canvas.rotate(15, px, py);

}

canvas.restore();

7. 为了查看指南针,修改main.xml资源,使用你的CompassView来替换TextView。这个过程将在下个章节中有更加详细的解释。

<?xml version=”1.0” encoding=”utf-8”?>

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”

android:orientation=”vertical”

android:layout_width=”fill_parent”

android:layout_height=”fill_parent”>

<com.paad.compass.CompassView

android:id=”@+id/compassView”

android:layout_width=”fill_parent”

android:layout_height=”fill_parent”

/>

</LinearLayout>

8. 运行Activity,你会看到指南针显示出来了。第10章中,你将了解如何绑定CompassView到设备的指南针。

Sample Code:
      http://files.cnblogs.com/xirihanlin/DL090723@cc-CompassView.zip

Sample图示:

创建指南针View的例子相关推荐

  1. Android官方开发文档Training系列课程中文版:创建自定义View之View的创建

    原文地址:http://android.xsoftlab.net/training/custom-views/index.html 引言 Android框架含有大量的View类,这些类用来显示各式各样 ...

  2. UIBezierPath和CAShapeLayer创建不规则View(Swift 3.0)

    最近一个朋友在做图片处理的 App,想要实现类似 MOLDIV App 拼图的UI效果(如何创建不规则的 view),就问我有什么想法.我首先想到的就是 UIBezierPath+CAShapeLay ...

  3. 《游戏设计师修炼之道:数据驱动的游戏设计》一2.3 创建漏洞:一个例子

    2.3 创建漏洞:一个例子 现在,让我们使用上文提到的所有项目设计一个场景,通过实际演练来了解善意程序造成的恶劣后果.本章开始提到的电子邮件程序就是个好例子.稍后,我们将按照SDLC的所有步骤,来看看 ...

  4. android 动态创建view,react-native动态创建Android View 无效果

    问题描述 react-native动态创建Android View 无效果,我想在react-native里面直接点击函数进行创建,也就是通过module中的方法创建View 问题出现的环境背景及自己 ...

  5. Fragment的onCreateView创建的view是如何加入到Activity的

    ** Fragment的onCreateView创建的view是如果加入到Activity的过程分析 ** 1.简单介绍一下fragment的使用 在activity的布局里添加一个ViewGroup ...

  6. Android官方开发文档Training系列课程中文版:创建自定义View之View的绘制

    原文地址:http://android.xsoftlab.net/training/custom-views/custom-drawing.html#draw 自定义View最重要的部分就是它的样子了 ...

  7. component是什么接口_【Android每日一题】从Activity创建到View呈现中间发生了什么?...

    前言 前段时间公司招人,作为面试官,我经常让面试者简述View的绘制流程.他们基本都能讲明白View的测量(measure).布局(layout).绘制(draw)等过程. 还有少数人会提到Decor ...

  8. php 创建文件编码,php fopen创建utf8编码文件例子

    如果我们直接使用fopen创建会发现文件编码都不是uft-8的了,那么如果要创建uft8文件我们需要进行一些技术处理,下面我搜索了网络上一些通用方法,下面一起来看看吧. 使用PHP创建编码格式为utf ...

  9. SAP ABAP实用技巧介绍系列之如何创建Maintenance view

    Created by Jerry Wang, last modified on Apr 18, 2014 1. Create a database table with type C( Customi ...

最新文章

  1. 汇编寄存器(内存访问)基础知识之三---mov指令
  2. 布巴内斯瓦尔成智慧城市 印小城何以“智慧”
  3. 22岁天才少女加入华为俄罗斯研究院,曾获「编程界奥赛」冠军
  4. spark sql定义RDD、DataFrame与DataSet
  5. mysql忽略数据类型_MYSQL 常用数据类型
  6. IOS-状态栏的简单操作
  7. 确认! Python夺冠,Java“被迫”退出竞争舞台,网友:崩溃!
  8. 测试用例集-8.公交卡测试用例
  9. oozie ErrorCode含义
  10. 【翻译】Drafting and Revision: Laplacian Pyramid Network for Fast High-Quality Artistic Style Transfer
  11. 灵格斯怎么屏幕取词_完整页灵格斯词霸怎么用,灵格斯词霸使用教程_9号资讯
  12. fastadmin 微信支付宝整合插件 支付宝APP支付 ALIN10146
  13. 解决NameError: name '__file__' is not defined的方法
  14. super_status_bar与status_bar的关系
  15. k-medoid(k中心点)聚类算法Python实现
  16. Redux DevTools工具的安装
  17. WEB 应用中的整体结构和层次关系
  18. W ndows7有线网络连接,七仔教你学Windows7:如何连接网络 爱问知识人
  19. 头文件stdio与stdlib.h的区别
  20. 17个案例印证5大生死逻辑

热门文章

  1. python字符串补空格输出_python实现指定字符串补全空格、前面填充0的方法
  2. 生产者消费者模型-管程法(Java)
  3. android自定义view案例,Android自定义View的实现方法实例详解
  4. mysql 键缓冲区_mysql:键缓存
  5. Halcon 二维码
  6. MHA高可用 MHA+Keepalive
  7. H5本地储存Web Storage
  8. jquery的一点点认识
  9. mongodb java驱动_Java操作MongoDB之mongodb-driver(一)
  10. [MyBatis]诡异的Invalid bound statement (not found)错误