`
jayghost
  • 浏览: 429473 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

创建指南针View的例子(1)

阅读更多

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

 

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

 

在第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类中。创建一个用来显示方向的属性并为它创建getset方法。

 

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

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics