您的位置:首页 > 移动开发 > Android开发

Android实战简易教程<四十六>(自定义控件体验之罗盘)

2015-09-26 11:22 513 查看


前言

作为一名有创新意思的开发人员,你迟早会发现内置的控件会满足不了你的想象力。

拥有扩展已存在的视图、组建复合的控件以及创建独特的新视图能力,可以创建出最适合自己应用程序工作流的有优美用户界面,让用户得到最优的体验。

创建新视图的最佳方法和希望达到的目标有关:

1.如果现有控件已经可以满足希望实现的基本功能,那么只需对现有控件的外观或行为进行修改或扩展即可。通过重写事件处理程序和onDraw()方法。

2.可以通过组合多个视图来创建不可分割的、可重用的控件,从而使它可以综合使用过个相关联的视图功能,比如一键清空TextView组合控件。

3.创建一个全新的控件。

下面我们通过一个小实例,创建一个罗盘界面来体验一下如何自定义控件。


一.创建自定义控件类Compass,继承View:

[java] view
plaincopy

package com.example.compass;



import android.content.Context;

import android.content.res.Resources;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.util.AttributeSet;

import android.view.View;

import android.view.accessibility.AccessibilityEvent;



public class Compass extends View {

private Paint makerPaint;

private Paint textPaint;

private Paint circlePaint;

private String north, south, east, west;

private int textHeight;



public Compass(Context context) {

super(context);

initCompassView();

}



public Compass(Context context, AttributeSet attrs) {

super(context, attrs);

initCompassView();

}



public Compass(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initCompassView();

}



private void initCompassView() {

setFocusable(true);

Resources r = this.getResources();

// 画圆

circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

circlePaint.setColor(r.getColor(R.color.background_color));

circlePaint.setStrokeWidth(1);

circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);



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

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

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

west = 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");



makerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿

makerPaint.setColor(r.getColor(R.color.maker_color));



}



@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int measureWidth = measure(widthMeasureSpec);

int measureHeight = measure(heightMeasureSpec);

int d = Math.min(measureHeight, measureWidth);

setMeasuredDimension(d, d);

}



private int measure(int measureSpec) {

int result = 0;

// 对测量说明进行解码

int speMode = MeasureSpec.getMode(measureSpec);

int speSize = MeasureSpec.getSize(measureSpec);



if (speMode == MeasureSpec.UNSPECIFIED) {

// 如果没有指定界限,则默认返回大小200

result = 200;

} else {

// 由于你希望填充可以的空间,所有总是返回整个可用的的边界

result = speSize;

}

return result;

}



//添加属性

private float bearing;



public float getBearing() {

return bearing;

}



public void setBearing(float _bearing) {

bearing = _bearing;

sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);//添加可访问性支持,罗盘显示方向

}



@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

int mMeasureWidth = getMeasuredWidth();

int mMeasureHeight = getMeasuredHeight();

int px = mMeasureWidth / 2;

int py = mMeasureHeight / 2;

int radius = Math.min(px, py);//去最小值作为半径;



// 绘制背景

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



canvas.save();

canvas.rotate(-bearing, px, py);// 旋转-bearing度角度;



// 绘制标记



int textWidth = (int) textPaint.measureText("W");

int cardinalX = px - textWidth / 2;

int cardinalY = py - radius + textHeight;



// 每15度绘制一个标记,每45度绘制一个文本



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

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

canvas.save();

canvas.translate(0, textHeight);



// 绘制基本方位

if (i % 6 == 0) {

String dirString = "";

switch (i) {

case 0:

dirString = north;

int arrowY = 2 * textHeight;

canvas.drawLine(px, arrowY, px - 5, 3 * textHeight, makerPaint);

canvas.drawLine(px, arrowY, px + 5, 3 * textHeight, makerPaint);

break;

case 6:

dirString = east;

break;

case 12:

dirString = south;

break;

case 18:

dirString = west;

break;



default:

break;

}

canvas.drawText(dirString, cardinalX, cardinalY, textPaint);

// 每45度绘制文本

} else if (i % 3 == 0) {

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



}



// 将当前方向用作可访问性事件使用的内容

@Override

public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {

super.dispatchPopulateAccessibilityEvent(event);

if (isShown()) {

String bearingStr = String.valueOf(bearing);

if (bearingStr.length() > AccessibilityEvent.MAX_TEXT_LENGTH)

bearingStr = bearingStr.substring(0, AccessibilityEvent.MAX_TEXT_LENGTH);

event.getText().add(bearingStr);

return true;

} else {

return false;

}



}



}

二、配置属性

[html] view
plaincopy

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

<resources>



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

<string name="hello_world">Hello world!</string>

<string name="action_settings">Settings</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>

[html] view
plaincopy

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

<resources>

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

<color name="maker_color">#AFFF</color>

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

</resources>



三、引入自定义控件

[html] view
plaincopy

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent" >



<com.example.compass.Compass

android:id="@+id/compass"

android:layout_width="match_parent"

android:layout_height="match_parent" />



</RelativeLayout>

[java] view
plaincopy

package com.example.compass;



import android.app.Activity;

import android.os.Bundle;



public class MainActivity extends Activity {



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Compass compass=(Compass) this.findViewById(R.id.compass);

compass.setBearing(0);

}





}

运行实例:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐