Android 如何自定义控件(继承View)

该例子演示的是如何自定义罗盘的控件

activity_mian.xml代码:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <com.paad.compass.CompassView
    android:id="@+id/compassView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
  />
</FrameLayout>

在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>

在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>

CompassView.java代码:

package com.paad.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 CompassView extends View {

  private float bearing;

  public void setBearing(float _bearing) {
    bearing = _bearing;
    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
  }

  public float getBearing() {
    return bearing;
  }

  private Paint markerPaint;
  private Paint textPaint;
  private Paint circlePaint;
  private String northString;
  private String eastString;
  private String southString;
  private String westString;
  private int textHeight;

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

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

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

  @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.  
       //如果没有指定界限,返回默认大小200
      result = 200;
    } else {
      // As you want to fill the available space
      // always return the full available bounds.
      result = specSize;
    }
    return result;
  }

  @Override
  protected void onDraw(Canvas canvas) {
    int mMeasuredWidth = getMeasuredWidth();
    int mMeasuredHeight = getMeasuredHeight();

    int px = mMeasuredWidth / 2;
    int py = mMeasuredHeight / 2 ;

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

    // Draw the background
    canvas.drawCircle(px, py, radius, circlePaint);

    // Rotate our perspective so that the 詔op' is
    // facing the current bearing.
    canvas.save();
    canvas.rotate(-bearing, px, py);

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

  @Override
  public boolean dispatchPopulateAccessibilityEvent(final 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;
  }
}

主要是重写onDraw方法和onMeasure方法来实现罗盘。

实现效果

源码下载链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值