先上效果
最近做的项目中的拍照模块要求拍照的时候手机是:
——竖直的
——面朝上的
——与地面的夹角为75°
基本上这个自定义控件就做了这样的一件事,如果手机的摆放位置符合上述条件,则会如图一所示,该控件中间的小圆显示在正中心的位置,整个控件是绿色的。
而如果摆放位置不符合条件,不是竖直的,夹角偏大偏小等,就会如图二图三所示,控件会变成红色而且中间的小圆也会做出对应的偏移提示用户当前应该往哪移动手机。
好,明白了需求就可以开始动工了,首先我们来温习一下自定义控件的基本知识。
自定义控件的基本步骤:
①新建一个类继承View。
②自定义属性,一个完美的自定义控件也可以添加xml来配置属性和风格。 要实现这一点,可按照下列步骤来做:
1) 添加自定义属性到xml文件中
2) 在xml的中,指定属性的值
3) 在view中获取xml中的值
4) 将获取的值应用到view中
③重写onMeasure(), onLayout(), onDraw(),方法(当然,简单一点的自定义控件只需要重写这几个就够了)。
④自定义监听器,选择合适的时机触发。
而手机的摆放位置信息我们可以使用手机的重力传感器来获得,图一中的X=。。。y=。。。z=。。。就是从手机的重力传感器获得的数据。
自定义控件GuideView所有代码:
package com.miser.sensordemo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
* 实现手机通过重力感应校准位置的自定义控件
* Created by Administrator on 2016/4/7.
*/
public class GuideView extends View {
private static final String TAG = "GuideView";
private Sensor mSensor;
private SensorManager mSensorManager;
private int mViewWidth;
private int mViewHeight;
//外面圆的线条宽度(px)
private float strokeWidth = 2;
//小圆圆心坐标
private float mChaildcy;
private float mChaildcx;
//里面圈圈的颜色,默认为红色
private int mColor = Color.RED;
public GuideView(Context context) {
super(context);
}
public GuideView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
//得到SensorManager对象
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
//获得重力感应传感器实例
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//注册监听器
mSensorManager.registerListener(mSensorEventListener, mSensor, SensorManager.SENSOR_DELAY_UI);
}
public GuideView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.d(TAG, "onMeasure");
mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(mViewWidth, mViewHeight);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.d(TAG, "onLayout");
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d(TAG, "onDraw");
//画外面的大圆-----------------
float cx = mViewWidth / 2;
float cy = mViewHeight / 2;
float radio = (mViewWidth > mViewHeight ? cx : cy) - strokeWidth;
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(mColor);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(cx, cy, radio, paint);
//----------------------------
//画里面的小圆-----------------
if ((mChaildcx > 0 && mChaildcx < mViewWidth)
&& (mChaildcy > 0 && mChaildcy < mViewHeight)) {
canvas.drawCircle(mChaildcx, mChaildcy, radio / 3, paint);
}
//----------------------------
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.d(TAG, "onDetachedFromWindow");
//取消重力感应的监听
mSensorManager.unregisterListener(mSensorEventListener);
}
/**
* 重力感应的监听器,可用来实时得到手机当前的位置信息
*/
SensorEventListener mSensorEventListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
float x = sensorEvent.values[SensorManager.DATA_X];
float y = sensorEvent.values[SensorManager.DATA_Y];
float z = sensorEvent.values[SensorManager.DATA_Z];
mChaildcx = mViewWidth / 2 - x * mViewWidth / 20;
if (z > 0) {
mChaildcy = mViewHeight / 2 + ((y - 8.3333f) * mViewHeight / 20);
} else {
mChaildcy = mViewHeight / 2 - (z * mViewHeight / 20);
}
if ((x > -1 && x < 1)//手机竖屏度在合适范围内
&& (y > 7.3F && y < 9.3)//倾斜15°范围内
&& (z > 0)//手机是面朝上的
) {
mColor = Color.GREEN;
} else {
mColor = Color.RED;
}
postInvalidate();
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
}
有自定义控件的代码应该就可以了,这里就不上demo了,如有疑惑可私信或邮件 miqingtang@163.com