一个简单的自定义Compass
来源:互联网 发布:ubuntu snmpwalk 安装 编辑:程序博客网 时间:2024/06/14 20:00
Android提供了sensor(传感器)sensorManager(传感器管理器)类,我们可以对相关服务的注册来进行传感器(加速度,磁场,方向等)的开发。
现在利用传感器写一个简单的指南针功能demo。
首先自定义一个旋转的imageview(存放根据水平度数变化的图片),
代码如下:
CompassView.java;
public class CompassView extends ImageView{
private Drawable compass; //旋转的图片资源
private float mDirection ; //方向旋转浮点数
public CompassView(Context context) {
super(context);
mDirection = 0f; //默认不旋转
compass=null;
}
public CompassView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mDirection = 0f;
compass=null;
}
public CompassView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDirection=0f;
compass=null;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(compass==null){
compass=getDrawable(); //获取当前view资源
compass.setBounds(0,0,getHeight(),getWidth()); //充满当前view
}
canvas.save();
canvas.rotate(mDirection ,getHeight() / 2,getWidth() / 2); //图片绕中心旋转
compass.draw(canvas); //将旋转之后的图片画出来,保持旋转之后的样子
canvas.restore(); //保存一下
}
/**
* 自定义旋转方法
* @param direction
*
* */
public void updateDirection(float direction){
mDirection=direction;
invalidate(); //旋转之后重新刷新
}
然后就是具体功能的实现了,也是重点。界面很简单,直接在MainActivity内实现所有功能包括引导动画,传感器的应用,主界面ui更新等
代码如下:
MainActivity.java;
public class MainActivity extends Activity(){
private static final int EXIT_TIME = 2000;// 两次按返回键的间隔判断
private final float MAX_ROATE_DEGREE = 1.0f;// 最多旋转一周,即360°
private SensorManager mSensorManager;// 传感器管理对象
private Sensor mOrientationSensor;// 传感器对象
private float mDirection;// 当前浮点方向
private float mTargetDirection;// 目标浮点方向
private AccelerateInterpolator mInterpolator;// 动画从开始到结束,变化率是一个加速的过程,就是一个动画速率
protected final Handler mHandler = new Handler();
private boolean mStopDrawing;// 是否停止指南针旋转的标志位
private long firstExitTime = 0L;// 用来保存第一次按返回键的时间private final float MAX_ROATE_DEGREE = 1.0f;// 最多旋转一周,即360°
private SensorManager mSensorManager;// 传感器管理对象
private Sensor mOrientationSensor;// 传感器对象
private float mDirection;// 当前浮点方向
private float mTargetDirection;// 目标浮点方向
private AccelerateInterpolator mInterpolator;// 动画从开始到结束,变化率是一个加速的过程,就是一个动画速率
protected final Handler mHandler = new Handler();
private boolean mStopDrawing;// 是否停止指南针旋转的标志位
private long firstExitTime = 0L;// 用来保存第一次按返回键的时间
View mCompassView; // 实际上是一个LinearLayout,装指南针ImageView和位置TextView
CompassView mPointer;// 自定义的指南针view
LinearLayout mDirectionLayout;// 顶部显示方向名称(东南西北)的LinearLayout
LinearLayout mAngleLayout; // 顶部显示方向具体度数的LinearLayout
View mViewGuide; //引导页
ImageView mGuideAnimation; //引导动画图片
protected Handler invisiableHandler = new Handler() {
public void handleMessage(Message msg) {
mViewGuide.setVisibility(View.GONE);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();// 初始化view
initServices();// 初始化传感器和位置服务
}
public void onWindowFocusChanged(boolean hasFocus) {
AnimationDrawable anim = (AnimationDrawable) mGuideAnimation
.getDrawable();
anim.start();
}
/**
* 更新指南针旋转的线程,每20毫秒检测方向变化值,对应更新指南针旋转
* */
protected Runnable mCompassViewUpdater = new Runnable() {
@Override
public void run() {
if (mPointer != null && !mStopDrawing) {
if (mDirection != mTargetDirection) {
// 计算短程序
float to = mTargetDirection;
if (to - mDirection > 180) {
to -= 360;
} else if (to - mDirection < -180) {
to += 360;
}
float distance = to - mDirection;
if (Math.abs(distance) > MAX_ROATE_DEGREE) {
distance = distance > 0 ? MAX_ROATE_DEGREE
: (-1.0f * MAX_ROATE_DEGREE);
}
// 加速动画去旋转图片,细节处理
mDirection = normalizeDegree(mDirection
+ ((to - mDirection) * mInterpolator
.getInterpolation(Math.abs(distance) > MAX_ROATE_DEGREE ? 0.4f
: 0.3f)));
mPointer.updateDirection(mDirection);// 更新指南针旋转
}
updateDirection();// 更新方向值
mHandler.postDelayed(mCompassViewUpdater, 20);// 20毫米后重新执行自己
}
}
};
/**
* 初始化view
* */
private void initViews() {
mViewGuide = findViewById(R.id.view_guide);
mViewGuide.setVisibility(View.VISIBLE);
invisiableHandler.sendMessageDelayed(new Message(), 3000);
mGuideAnimation = (ImageView) findViewById(R.id.guide_animation);
mDirection = 0.0f;// 初始化起始方向
mTargetDirection = 0.0f;// 初始化目标方向
mInterpolator = new AccelerateInterpolator();// 实例化加速动画对象
mStopDrawing = true;
mCompassView = findViewById(R.id.view_compass);
mPointer = (CompassView) findViewById(R.id.compass_pointer);
mDirectionLayout = (LinearLayout) findViewById(R.id.layout_direction);
mAngleLayout = (LinearLayout) findViewById(R.id.layout_angle);
}
// 初始化传感器
private void initServices() {
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mOrientationSensor = mSensorManager.getSensorList(
Sensor.TYPE_ORIENTATION).get(0);
}
/**
* 监听返回键
* */
@Override
public void onBackPressed() {// 覆盖返回键
long curTime = System.currentTimeMillis();
if (curTime - firstExitTime < EXIT_TIME) {// 两次按返回键的时间小于2秒就退出应用
finish();
} else {
Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
firstExitTime = curTime;
}
}
/**
* 在恢复的生命周期里判断、启动传感器服务
* */
@Override
protected void onResume() {
super.onResume();
if (mOrientationSensor != null) {
mSensorManager.registerListener(mOrientationSensorEventListener,
mOrientationSensor, SensorManager.SENSOR_DELAY_GAME);
}
mStopDrawing = false;
mHandler.postDelayed(mCompassViewUpdater, 20);// 20毫秒执行一次更新指南针图片旋转
}
/**
* 在暂停的生命周期里注销传感器服务
* */
@Override
protected void onPause() {
super.onPause();
mStopDrawing = true;
if (mOrientationSensor != null) {
mSensorManager.unregisterListener(mOrientationSensorEventListener);
}
}
// 更新顶部方向显示的方法
private void updateDirection() {
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
// 先移除layout中所有的view
mDirectionLayout.removeAllViews();
mAngleLayout.removeAllViews();
// 根据mTargetDirection,作方向名称图片的处理
ImageView east = null;
ImageView west = null;
ImageView south = null;
ImageView north = null;
float direction = normalizeDegree(mTargetDirection * -1.0f);
if (direction > 22.5f && direction < 157.5f) {
// east
east = new ImageView(this);
east.setImageResource( R.drawable.e);
east.setLayoutParams(lp);
} else if (direction > 202.5f && direction < 337.5f) {
// west
west = new ImageView(this);
west.setImageResource(R.drawable.w);
west.setLayoutParams(lp);
}
if (direction > 112.5f && direction < 247.5f) {
// south
south = new ImageView(this);
south.setImageResource(R.drawable.s);
south.setLayoutParams(lp);
} else if (direction < 67.5 || direction > 292.5f) {
// north
north = new ImageView(this);
north.setImageResource(R.drawable.n);
north.setLayoutParams(lp);
}
if (south != null) {
mDirectionLayout.addView(south);
}
if (north != null) {
mDirectionLayout.addView(north);
}
if (east != null) {
mDirectionLayout.addView(east);
}
if (west != null) {
mDirectionLayout.addView(west);
}
// 下面是根据方向度数显示度数图片数字
int direction2 = (int) direction;
boolean show = false;
if (direction2 >= 100) {
mAngleLayout.addView(getNumberImage(direction2 / 100));
direction2 %= 100;
show = true;
}
if (direction2 >= 10 || show) {
mAngleLayout.addView(getNumberImage(direction2 / 10));
direction2 %= 10;
}
mAngleLayout.addView(getNumberImage(direction2));
// 下面是增加一个°的图片
ImageView degreeImageView = new ImageView(this);
degreeImageView.setImageResource(R.drawable.degree);
degreeImageView.setLayoutParams(lp);
mAngleLayout.addView(degreeImageView);
}
/**
* 获取方向度数对应的图片,返回ImageView
* */
private ImageView getNumberImage(int number) {
ImageView image = new ImageView(this);
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
switch (number) {
switch (number) {
case 0:
image.setImageResource(R.drawable.number_0);
break;
case 1:
image.setImageResource(R.drawable.number_1);
break;
case 2:
image.setImageResource(R.drawable.number_2);
break;
case 3:
image.setImageResource(R.drawable.number_3);
break;
case 4:
image.setImageResource(R.drawable.number_4);
break;
case 5:
image.setImageResource(R.drawable.number_5);
break;
case 6:
image.setImageResource(R.drawable.number_6);
break;
case 7:
image.setImageResource(R.drawable.number_7);
break;
case 8:
image.setImageResource(R.drawable.number_8);
break;
case 9:
image.setImageResource(R.drawable.number_9);
break;
}
image.setLayoutParams(lp);
return image;
}
/**
* 方向传感器变化监听
* */
private SensorEventListener mOrientationSensorEventListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
float direction = event.values[mSensorManager.DATA_X] * -1.0f;
mTargetDirection = normalizeDegree(direction);// 赋值给全局变量,让指南针旋转
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
/**
* 调整方向传感器获取的值
*/
private float normalizeDegree(float degree) {
return (degree + 720) % 360;
}
}
功能代码就这些,主界面上方是一个显示方向的LinearLayout,中间用来存放罗盘图片的自定义compassview,图片上是动态改变显示度数的LinearLayout,资源文件就不贴了。
效果图:
- 一个简单的自定义Compass
- Compass的一个简单例子
- 利用Compass实现一个简单的搜索引擎
- 利用Compass实现一个简单的搜索引擎
- 利用Compass实现一个简单的搜索引擎
- 利用Compass实现一个简单的搜索引擎
- 利用Compass实现一个简单的搜索引擎
- 利用Compass实现一个简单的搜索引擎[转贴]
- 简单的lucene框架 Compass 的使用
- 一个简单的自定义Collection
- 自定义一个简单的ScrollView
- 一个简单的自定义popupwindow
- 自定义一个简单的PopupWindow
- 一个简单的自定义TopBar
- 一个简单的自定义SwitchButton
- 一个简单的自定义控件
- 一个简单的自定义Dialog
- 一个简单的自定义DialogFragment
- 多线程使用linux时间函数的方法
- Server报错:java.lang.IllegalStateException: Cannot create a session after the response has been commit
- UFLDL教程: Exercise: Implement deep networks for digit classification
- java生成二维码-QRCode.jar
- MATLAB量化浮点数
- 一个简单的自定义Compass
- placeholder 兼容 ie6/7/8/9
- mysql 建库,授权操作
- 动态规划入门
- 如何将明细表中统计好数量 全部更新到 汇总表对应的字段 sql
- Windows系统安装搭建ios开发环境
- EditText禁止输入空格、换行符或特殊字符
- 【OpenCV】图像显示
- tcp_timetou 解决方案