Android自定义控件实现方向盘效果
程序员文章站
2023-11-09 20:02:58
在很多开发中,为了界面更加的友好,在自定义view的基础上,开发者会开发出各种各样的自定义控件来满足实际开发需要,其中有一种”方向盘”的控件在实际开发中非常常见,便于用户进行一些实际性的方向控制。在复...
在很多开发中,为了界面更加的友好,在自定义view的基础上,开发者会开发出各种各样的自定义控件来满足实际开发需要,其中有一种”方向盘”的控件在实际开发中非常常见,便于用户进行一些实际性的方向控制。
在复习参考了许多自定义控件的基础上,我实现了一个最最基本的方向盘空间,并且可以根据方向做出相应的反应。话不多说,先看看效果。
做的有点丑,大家可以看看实际原理,后期再优化具体“方向盘”.
空间下面的几行字是我为了确定方向所写的一些参数,基本思想就是在方向盘的中心确定一个坐标轴,根据中间这个小圆的和中心点的距离与方向确定所处的方向。在手离开屏幕以后,小圆回到原点。
一言不合就放代码~~~~
具体是怎么实现的呢??
来我们一起看看代码,看完一目了然。
package com.sshhsun.socketudp.utils; import android.annotation.suppresslint; import android.content.context; import android.graphics.canvas; import android.graphics.color; import android.graphics.paint; import android.util.attributeset; import android.util.log; import android.view.motionevent; import android.view.view; public class mywheel extends view implements runnable,view.ontouchlistener { public mywheel(context context) { super(context); // todo auto-generated constructor stub } //先定义一些绘图要用的基本参数 public static final int bottom = 7; public static final int bottom_left = 8; public static final long default_loop_interval = 100l; public static final int front = 3; public static final int front_right = 4; public static final int left = 1; public static final int left_front = 2; public static final int right = 5; public static final int right_bottom = 6; private final double rad = 57.295779500000002d; private paint button; private int buttonradius; public double centerx = 0.0d; public double centery = 0.0d; private paint horizontalline; private int joystickradius; private int lastangle = 0; private int lastpower = 0; private long loopinterval = 100l; private paint maincircle; //整个控件的大圆,及小红点的活动范围 //自定义的接口用于监听处理控件的触摸事件 private onmywheelmovelistener onmywheelmovelistener; private paint secondarycircle;//第二个内圆,小红圆超过后开始处理角度 private thread thread = new thread(this); private paint verticalline; private int xposition = 0; private int yposition = 0; private static final string tag="mywheel"; public mywheel(context paramcontext, attributeset paramattributeset) { super(paramcontext, paramattributeset); initmywheel(); //好吧,我知道mywheel这个名字有点太随便了........ } public mywheel(context paramcontext, attributeset paramattributeset, int paramint) { super(paramcontext, paramattributeset, paramint); initmywheel(); } //根据所处的位置得到角度 private int getangle() { if (this.xposition > this.centerx) { if (this.yposition < this.centery) { int m = (int) (90.0d + 57.295779500000002d * math .atan((this.yposition - this.centery) / (this.xposition - this.centerx))); this.lastangle = m; return m; } if (this.yposition > this.centery) { int k = 90 + (int) (57.295779500000002d * math .atan((this.yposition - this.centery) / (this.xposition - this.centerx))); this.lastangle = k; return k; } this.lastangle = 90; return 90; } if (this.xposition < this.centerx) { if (this.yposition < this.centery) { int j = (int) (57.295779500000002d * math .atan((this.yposition - this.centery) / (this.xposition - this.centerx)) - 90.0d); this.lastangle = j; return j; } if (this.yposition > this.centery) { int i = -90 + (int) (57.295779500000002d * math .atan((this.yposition - this.centery) / (this.xposition - this.centerx))); this.lastangle = i; return i; } this.lastangle = -90; return -90; } if (this.yposition <= this.centery) { this.lastangle = 0; return 0; } if (this.lastangle < 0) { this.lastangle = -180; return -180; } this.lastangle = 180; return 180; } //根据红色圆的距离和角度得到方向 private int getdirection() { int k; int j = 0; int i; if ((this.lastpower == 0) && (this.lastangle == 0)) { k = 0; return k; } if (this.lastangle <= 0) j = 90 + -1 * this.lastangle; while (true) { k = 1 + (j + 22) / 45; if (k <= 8) { break; } if (this.lastangle <= 90) { j = 90 - this.lastangle; continue; } j = 360 - (-90 + this.lastangle); } return k; } //得到红色圆与中心的距离 private int getpower() { return (this.lastpower=(int) (100.0d * math.sqrt((this.xposition - this.centerx) * (this.xposition - this.centerx) + (this.yposition - this.centery) * (this.yposition - this.centery)) / this.joystickradius)); } private int measure(int paramint) { int i = view.measurespec.getmode(paramint); int j = view.measurespec.getsize(paramint); if (i == 0) return 200; return j; } //初始化一些基本参数 protected void initmywheel() { this.maincircle = new paint(1); this.maincircle.setcolor(color.blue); this.maincircle.setstrokewidth(3.0f); this.maincircle.setstyle(paint.style.stroke); this.secondarycircle = new paint(); this.secondarycircle.setcolor(-16711936); this.secondarycircle.setstrokewidth(3.0f); this.secondarycircle.setstyle(paint.style.stroke); this.verticalline = new paint(); this.verticalline.setstrokewidth(5.0f); this.verticalline.setcolor(-65536); this.horizontalline = new paint(); this.horizontalline.setstrokewidth(2.0f); this.horizontalline.setcolor(-16777216); this.button = new paint(1); this.button.setcolor(color.red); this.button.setstyle(paint.style.fill); } //初始化以后绘制方向盘。 protected void ondraw(canvas paramcanvas) { this.centerx = (getwidth() / 2); this.centery = (getheight() / 2); paramcanvas.drawcircle((int) this.centerx, (int) this.centery, this.joystickradius, this.maincircle); paramcanvas.drawcircle((int) this.centerx, (int) this.centery, this.joystickradius / 2, this.secondarycircle); paramcanvas .drawline((float) this.centerx, (float) this.centery, (float) this.centerx, (float) (this.centery - this.joystickradius), this.verticalline); paramcanvas.drawline((float) (this.centerx - this.joystickradius), (float) this.centery, (float) (this.centerx + this.joystickradius), (float) this.centery, this.horizontalline); paramcanvas .drawline((float) this.centerx, (float) (this.centery + this.joystickradius), (float) this.centerx, (float) this.centery, this.horizontalline); paramcanvas.drawcircle(this.xposition, this.yposition, this.buttonradius, this.button); } protected void onfinishinflate() { } protected void onmeasure(int paramint1, int paramint2) { int i = math.min(measure(paramint1), measure(paramint2)); setmeasureddimension(i, i); } protected void onsizechanged(int paramint1, int paramint2, int paramint3, int paramint4) { super.onsizechanged(paramint1, paramint2, paramint3, paramint4); this.xposition = (getwidth() / 2); this.yposition = (getwidth() / 2); int i = math.min(paramint1, paramint2); this.buttonradius = (int) (0.20d * (i / 2)); this.joystickradius = (int) (0.75d * (i / 2)); } @override public boolean ontouchevent(motionevent parammotionevent) { //根据手触碰的坐标决定红色小圆的位置 this.xposition = (int) parammotionevent.getx(); this.yposition = (int) parammotionevent.gety(); double d = math.sqrt((this.xposition - this.centerx) * (this.xposition - this.centerx) + (this.yposition - this.centery) * (this.yposition - this.centery)); if (d > this.joystickradius) { this.xposition = (int) ((this.xposition - this.centerx) * this.joystickradius / d + this.centerx); this.yposition = (int) ((this.yposition - this.centery) * this.joystickradius / d + this.centery); } invalidate();//再重新绘制 if (parammotionevent.getaction() == 1) { this.xposition = (int) this.centerx; this.yposition = (int) this.centery; this.thread.interrupt(); if (this.onmywheelmovelistener != null) this.onmywheelmovelistener.onvaluechanged(getangle(), getpower()); } if ((this.onmywheelmovelistener != null) && (parammotionevent.getaction() == 0)) { if ((this.thread != null) && (this.thread.isalive())) this.thread.interrupt(); this.thread = new thread(this); this.thread.start(); if (this.onmywheelmovelistener != null) //自定义接口处理触摸事件 this.onmywheelmovelistener.onvaluechanged(getangle(), getpower()); } return true; } @override public void run() { while (true) { if (thread.interrupted()) return; post(new runnable() { public void run() { // log.e(tag, "运行在"+thread.currentthread().getname()+"线程中"); if (mywheel.this.onmywheelmovelistener != null) mywheel.this.onmywheelmovelistener.onvaluechanged( mywheel.this.getangle(), mywheel.this.getpower()); } }); try { thread.sleep(this.loopinterval); } catch (interruptedexception localinterruptedexception) { } } } public void setonmywheelmovelistener( onmywheelmovelistener paramonjoystickmovelistener, long paramlong) { this.onmywheelmovelistener = paramonjoystickmovelistener; this.loopinterval = paramlong; } public static abstract interface onmywheelmovelistener { public abstract void onvaluechanged(int paramint1, int paramint2); } @suppresslint("clickableviewaccessibility") @override public boolean ontouch(view v, motionevent event) { /*处理这个控件的触摸事件*/ return true; } }
怎么用?下面我给出我的调用实例进行讲解
首先在xml文件中应用。
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" > <linearlayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <button android:id="@+id/simple_rest" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="蹲下" /> <button android:id="@+id/simple_stand" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="站立" /> <button android:id="@+id/simple_standinit" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="准备" /> <button android:id="@+id/simple_sit" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="坐下" /> <button android:id="@+id/simple_standzero " android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="零态" /> </linearlayout> <com.sshhsun.socketudp.utils.mywheel android:id="@+id/mywheel" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <textview android:id="@+id/notice" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="这是简单控制界面" /> <linearlayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <seekbar android:id="@+id/turns" android:layout_width="match_parent" android:layout_height="wrap_content" android:minheight="3dp" android:minwidth="260dp" android:progress="100" /> </linearlayout> </linearlayout>
在一个fragment中引用实例并处理相应监听事件。
package com.sshhsun.socketudp.fragment; import android.content.context; import android.os.bundle; import android.os.vibrator; import android.support.v4.app.fragment; import android.util.log; import android.view.layoutinflater; import android.view.view; import android.view.viewgroup; import android.webkit.webview.findlistener; import android.widget.button; import android.widget.seekbar; import android.widget.seekbar.onseekbarchangelistener; import android.widget.textview; import android.widget.toast; import com.sshhsun.socketudp.r; import com.sshhsun.socketudp.activity.constant.constant; import com.sshhsun.socketudp.utils.mywheel; import com.sshhsun.socketudp.utils.mywheel.onmywheelmovelistener; import com.sshhsun.socketudp.utils.udputil; public class simplefragment extends fragment implements view.onclicklistener { private mywheel mtwheel; private textview notice; private textview show; private string direction = "none"; private seekbar seekbar; private static final string tag = "simplefragment"; vibrator vibator; private context context = getactivity(); private boolean isturn = false; private button stand; private button sit; private button standinit; private button rest; private button standzero; private udputil udputil; private boolean issend = false; private boolean isstop = true; @override public view oncreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) { return initview(inflater, container, savedinstancestate); } @override public void onactivitycreated(bundle savedinstancestate) { super.onactivitycreated(savedinstancestate); initdata(); initlistener(); } public view initview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) { view view = inflater.inflate(r.layout.frag_simple, null); //我的方向盘控件mtwheel mtwheel = (mywheel) view.findviewbyid(r.id.mywheel); //控件下面的提示信息notice,其他控件大家可以忽略. notice = (textview) view.findviewbyid(r.id.notice); seekbar = (seekbar) view.findviewbyid(r.id.turns); seekbar.setprogress(50); stand = (button) view.findviewbyid(r.id.simple_stand); sit = (button) view.findviewbyid(r.id.simple_sit); standinit = (button) view.findviewbyid(r.id.simple_standinit); rest = (button) view.findviewbyid(r.id.simple_rest); standzero = (button) view.findviewbyid(r.id.simple_standzero); return view; } public void initlistener() { sit.setonclicklistener(this); standinit.setonclicklistener(this); rest.setonclicklistener(this); standzero.setonclicklistener(this); stand.setonclicklistener(this); //下面的监听器代码最为重要!!!!!!!! mtwheel.setonmywheelmovelistener(new onmywheelmovelistener() { @override // paramint1:角度 // paramint2:距离 根据这两个参数可以算出方向盘的方位 public void onvaluechanged(int paramint1, int paramint2) { boolean isdistance = false; if (paramint2 >= 50) { isdistance = true; int temp = math.abs(paramint1); if (paramint1 >= 0) { if (temp > 50 && temp < 120) { direction = "right"; if (!issend) { udputil.udpsend(direction, constant.port); issend = true; isstop = false; } } else if (temp < 40) { direction = "forward"; if (!issend) { udputil.udpsend(direction, constant.port); issend = true; isstop = false; } } else if (temp > 140) { direction = "back"; if (!issend) { udputil.udpsend(direction, constant.port); issend = true; isstop = false; } } else { direction = "指向不明确"; issend = false; } } else { if (temp > 50 && temp < 120) { direction = "left"; if (!issend) { udputil.udpsend(direction, constant.port); issend = true; isstop = false; } } else if (temp < 40) { direction = "forward"; if (!issend) { udputil.udpsend(direction, constant.port); issend = true; isstop = false; } } else if (temp > 140) { direction = "back"; if (!issend) { udputil.udpsend(direction, constant.port); issend = true; isstop = false; } } else { direction = "指向不明确"; issend = false; } } } else { isdistance = false; direction = "stop"; issend = false; } notice.settext(" getangle:" + paramint1 + "\n" + " getpower:" + paramint2 + "\n" + "direction:" + direction); if (direction.equals("stop") && (!isstop)) { udputil.udpsend(direction, constant.port); isstop = true; } } }, 100l); seekbar.setonseekbarchangelistener(new onseekbarchangelistener() { @override public void onstoptrackingtouch(seekbar seekbar) { seekbar.setprogress(50); isturn = false; string command = "stop"; udputil.udpsend(command, constant.port); } @override public void onstarttrackingtouch(seekbar seekbar) { } @override public void onprogresschanged(seekbar seekbar, int progress, boolean fromuser) { int cucrrent = seekbar.getprogress(); string command = "hello"; if (cucrrent < 20) { toast.maketext(getactivity(), "onprogresschanged" + "左转", 0) .show(); if (!isturn) { log.e(tag, "onprogresschanged" + "左转"); command = "turnleft"; udputil.udpsend(command, constant.port); vibator.vibrate(100); isturn = true; } } else if (cucrrent > 80) { toast.maketext(getactivity(), "onprogresschanged" + "右转", 0) .show(); if (!isturn) { log.e(tag, "onprogresschanged" + "右转"); command = "turnright"; udputil.udpsend(command, constant.port); vibator.vibrate(100); isturn = true; } } } }); } public void initdata() { udputil = new udputil(constant.address); vibator = (vibrator) getactivity().getsystemservice( context.vibrator_service); thread.currentthread().setname(tag); } public void processclick(view v) { string command = "hello"; switch (v.getid()) { case r.id.simple_rest: command = "rest"; break; case r.id.simple_sit: command = "sit"; break; case r.id.simple_stand: command = "stand"; break; case r.id.simple_standinit: command = "standinit"; break; case r.id.simple_standzero: command = "standzero"; break; default: break; } udputil.udpsend(command, constant.port); } @override public void onclick(view v) { processclick(v); } @override public void ondestroy() { super.ondestroy(); vibator.cancel(); } // @override // public boolean ontouch(view v, motionevent event) { // if (v.getid() == r.id.turns) { // string notice = ""; // switch (event.getaction()) { // case motionevent.action_down: // notice = "action_down"+event.getx(); // int process=(int) math.floor(event.getx()+0.5); // seekbar.setprogress(process); // break; // case motionevent.action_up: // notice = "action_up"; // break; // case motionevent.action_cancel: // notice = "action_cancel"; // break; // default: // break; // } // if (!textutils.isempty(notice)) { // toast.maketext(getactivity(), notice, 0).show(); // } // } // return true; // } }
声明一下:
1.上面的控件代码(第一部分代码)可以实际使用
2.第二部分代码演示了控件的使用与处理
3.关于控件的实现原理和思想在代码与注释中已经详细标记
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 详细分解交换机的口令恢复的十个步骤