我是靠谱客的博主 欢呼雪碧,这篇文章主要介绍Android自定义控件实现方向盘效果,现在分享给大家,希望可以做个参考。

在很多开发中,为了界面更加的友好,在自定义View的基础上,开发者会开发出各种各样的自定义控件来满足实际开发需要,其中有一种”方向盘”的控件在实际开发中非常常见,便于用户进行一些实际性的方向控制。

在复习参考了许多自定义控件的基础上,我实现了一个最最基本的方向盘空间,并且可以根据方向做出相应的反应。话不多说,先看看效果。

做的有点丑,大家可以看看实际原理,后期再优化具体“方向盘”.

空间下面的几行字是我为了确定方向所写的一些参数,基本思想就是在方向盘的中心确定一个坐标轴,根据中间这个小圆的和中心点的距离与方向确定所处的方向。在手离开屏幕以后,小圆回到原点。

一言不合就放代码~~~~

具体是怎么实现的呢??

来我们一起看看代码,看完一目了然。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
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文件中应用。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<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中引用实例并处理相应监听事件。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
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.关于控件的实现原理和思想在代码与注释中已经详细标记

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持靠谱客。

最后

以上就是欢呼雪碧最近收集整理的关于Android自定义控件实现方向盘效果的全部内容,更多相关Android自定义控件实现方向盘效果内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(141)

评论列表共有 0 条评论

立即
投稿
返回
顶部