一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Android - Android中SurfaceView和view畫出觸摸軌跡

Android中SurfaceView和view畫出觸摸軌跡

2021-06-21 17:49Android開發網 Android

這篇文章主要介紹了Android中SurfaceView和view畫出觸摸軌跡的相關資料,需要的朋友可以參考下

一、引言
         想實現一個空白的畫板,上面可以畫出手滑動的軌跡,就這么一個小需求。一般就來講就兩種實現方式,view或者surfaceview。下面看看兩種是如何實現的。
二、實現原理
         先簡單說一下實現原理:
       (1)用一張白色的bitmap作為畫板
       (2)用canvas在bitmap上畫線
       (3)為了畫出平滑的曲線,要用canvas的drawpath(path,paint)方法。
       (4)同時使用貝塞爾曲線來使曲線更加平滑
三、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
package picturegame.view;
 
import android.annotation.suppresslint;
import android.content.context;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.paint.style;
import android.graphics.path;
import android.util.attributeset;
import android.view.motionevent;
import android.view.view;
 
import com.winton.picturegame.r;
 
/**
* @classname: gameview
* @description: todo(這里用一句話描述這個類的作用)
* @author winton [email protected]
* @date 2015年9月26日 上午8:54:37
*
*/
public class gameview extends view{
  
 private paint paint = null; //
  
 private bitmap originalbitmap = null;//原始圖
  
 private bitmap new1bitmap = null;
  
 private bitmap new2bitmap = null;
  
 private float clickx =0;
  
 private float clicky=0;
  
 private float startx=0;
  
 private float starty=0;
  
 private boolean ismove = true;
  
 private boolean isclear = false;
  
 private int color =color.red;//默認畫筆顏色
  
 private float strokewidth =20f;//默認畫筆寬度
  
 path mpath;
  
  
 
 public gameview(context context) {
  this(context,null);
  // todo auto-generated constructor stub
 }
 public gameview(context context,attributeset atts) {
  this(context,atts,0);
  // todo auto-generated constructor stub
 }
 @suppresswarnings("static-access")
 public gameview(context context,attributeset atts,int defstyle) {
  super(context,atts,defstyle);
  // todo auto-generated constructor stub
   
  originalbitmap = bitmapfactory.decoderesource(getresources(), r.drawable.default_pic).copy(bitmap.config.argb_8888, true);//白色的畫板
  new1bitmap=originalbitmap.createbitmap(originalbitmap);
  mpath=new path();
 }
 
 //清楚
 @suppresswarnings("static-access")
 public void clear(){
  isclear =true;
  new2bitmap=originalbitmap.createbitmap(originalbitmap);
  invalidate();//重置
 }
  
 public void setstrokewidth(float width){
  this.strokewidth=width;
  initpaint();
 }
 @override
 protected void ondraw(canvas canvas) {
  // todo auto-generated method stub
  super.ondraw(canvas);
  canvas.drawbitmap(writer(new1bitmap),0,0, null);
   
 }
  
 @suppresslint("clickableviewaccessibility")
 @override
 public boolean ontouchevent(motionevent event) {
  // todo auto-generated method stub
   
   
  clickx =event.getx();
   
  clicky=event.gety();
   
  if(event.getaction()==motionevent.action_down){
   //手指點下屏幕時觸發
    
   startx=clickx;
   starty=clicky;
   mpath.reset();
   mpath.moveto(clickx, clicky);
    
//   ismove =false;
//   invalidate();
//   return true;
  }
  else if(event.getaction()==motionevent.action_move){
   //手指移動時觸發
   float dx=math.abs(clickx-startx);
   float dy=math.abs(clicky-starty);
//   if(dx>=3||dy>=3){
    //設置貝塞爾曲線的操作點為起點和終點的一半
    float cx = (clickx + startx) / 2;
    float cy = (clicky + starty) / 2;
    mpath.quadto(startx,starty, cx, cy);
     
    startx=clickx;
    starty=clicky;
     
//   }
//   ismove =true;
//   invalidate();
//   return true;
  }
   
   
  invalidate();
  return true;
 }
  
 
 /**
 * @title: writer
 * @description: todo(這里用一句話描述這個方法的作用)
 * @param @param pic
 * @param @return 設定文件
 * @return bitmap 返回類型
 * @throws
 */
 public bitmap writer(bitmap pic){
  initpaint();
   
  canvas canvas =null;
  if(isclear){
   canvas=new canvas(new2bitmap);
  }else{
   canvas=new canvas(pic);
  }
   
   //canvas.drawline(startx, starty, clickx, clicky, paint);//畫線
   canvas.drawpath(mpath, paint);
  if(isclear){
   return new2bitmap;
  }
  return pic;
 }
  
 private void initpaint(){
   
  paint = new paint();//初始化畫筆
   
  paint.setstyle(style.stroke);//設置為畫線
   
  paint.setantialias(true);//設置畫筆抗鋸齒
   
  paint.setcolor(color);//設置畫筆顏色
   
  paint.setstrokewidth(strokewidth);//設置畫筆寬度
 }
  
  
 /**
 * @title: setcolor
 * @description: todo(設置畫筆顏色)
 * @param @param color 設定文件
 * @return void 返回類型
 * @throws
 */
 public void setcolor(int color){
   
  this.color=color;
  initpaint();
 }
  
 public bitmap getpaint(){
  return new1bitmap;
 }
}

看一下效果:

Android中SurfaceView和view畫出觸摸軌跡

基本滿足需求
三、surfaceview實現

?
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
package picturegame.view;
 
import android.content.context;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.paint;
import android.graphics.paint.style;
import android.graphics.path;
import android.util.attributeset;
import android.view.motionevent;
import android.view.surfaceholder;
import android.view.surfaceholder.callback;
import android.view.surfaceview;
 
import com.winton.picturegame.r;
 
public class gameviewsurface extends surfaceview implements callback,runnable{
  
  
 /** 控制游戲更新循環 **/
 boolean mrunning = false;
  
 /**控制游戲循環**/
 boolean misrunning = false;
  
 /**每50幀刷新一次屏幕**/
 public static final int time_in_frame = 50;
 
 private int paintcolor=android.graphics.color.white;//默認畫筆顏色為黑色
  
 private float paintwidth=2f;//默認畫筆寬度
  
 private style paintstyle=style.stroke;//默認畫筆風格
  
 private int paintalph=255;//默認不透明
  
 private path mpath;//軌跡
  
 private paint mpaint;//畫筆
  
 private float startx=0.0f;//初始x
  
 private float starty=0.0f;//初始y
  
 private surfaceholder surfaceholder;
  
 public canvas mcanvas;
  
 public boolean first=true;
  
 bitmap bg;
  
 public gameviewsurface(context context){
  this(context,null);
 }
 public gameviewsurface(context context,attributeset attrs){
  this(context,attrs,0);
 }
 public gameviewsurface(context context, attributeset attrs, int defstyle) {
  super(context, attrs, defstyle);
  // todo auto-generated constructor stub
  this.setfocusable(true);//設置當前view擁有觸摸事件
   
  surfaceholder=getholder();
  surfaceholder.addcallback(this);
   
  mpath=new path();
  initpaint();
   
  bg = bitmapfactory.decoderesource(getresources(), r.drawable.default_pic).copy(bitmap.config.argb_8888, true);//白色的畫板
 }
 /**
 * @title: initpaint
 * @description: todo(初始化畫筆)
 * @param  設定文件
 * @return void 返回類型
 * @throws
 */
 private void initpaint(){
  mpaint=new paint();
  mpaint.setantialias(true);//消除鋸齒
  mpaint.setcolor(paintcolor);//畫筆顏色
  mpaint.setalpha(paintalph);//畫筆透明度
  mpaint.setstyle(paintstyle);//設置畫筆風格
  mpaint.setstrokewidth(paintwidth);//設置畫筆寬度
 }
  
 public void dodraw(){
  mcanvas=surfaceholder.lockcanvas();
  mcanvas.drawpath(mpath, mpaint);//繪制
  surfaceholder.unlockcanvasandpost(mcanvas);
 
 @override
 public boolean ontouchevent(motionevent event) {
  // todo auto-generated method stub
   
  switch (event.getaction()) {
  case motionevent.action_down:
   //手接觸屏幕時觸發
   dotouchdown(event);
   break;
  case motionevent.action_move:
   //手滑動時觸發
   dotouchmove(event);
   break;
    
  case motionevent.action_up:
   //手抬起時觸發
    
   break;
    
 
  default:
   break;
  }
  return true;
 }
  
 /**
 * @title: dotouchdown
 * @description: todo(手觸摸到屏幕時需要做的事情)
 * @param @param event 設定文件
 * @return void 返回類型
 * @throws
 */
 private void dotouchdown(motionevent event){
   
  float touchx=event.getx();
  float touchy=event.gety();
  startx=touchx;
  starty=touchy;
  mpath.reset();
  mpath.moveto(touchx, touchy);
 }
  
 /**
 * @title: dotouchmove
 * @description: todo(手在屏幕上滑動時要做的事情)
 * @param @param event 設定文件
 * @return void 返回類型
 * @throws
 */
 private void dotouchmove(motionevent event){
   
  float touchx=event.getx();
  float touchy=event.gety();
   
  float dx=math.abs(touchx-startx);//移動的距離
   
  float dy =math.abs(touchy-startx);//移動的距離
   
  if(dx>3||dy>3){
   float cx=(touchx+startx)/2;
   float cy=(touchy+starty)/2;
   mpath.quadto(startx, starty, cx, cy);
    
   startx=touchx;
   starty=touchy;
    
  }
   
 }
  
 public void setpaintcolor(int paintcolor) {
  this.paintcolor = paintcolor;
  initpaint();
 }
 public void setpaintwidth(float paintwidth) {
  this.paintwidth = paintwidth;
  initpaint();
 }
 public void setpaintstyle(style paintstyle) {
  this.paintstyle = paintstyle;
  initpaint();
 }
 public void setpaintalph(int paintalph) {
  this.paintalph = paintalph;
  initpaint();
 }
  
  
 @override
 public void run() {
  // todo auto-generated method stub
  while (misrunning) {
    
   /** 取得更新游戲之前的時間 **/
   long starttime = system.currenttimemillis();
   /** 在這里加上線程安全鎖 **/
   synchronized(surfaceholder){
    dodraw();
   }
    
   /** 取得更新游戲結束的時間 **/
   long endtime = system.currenttimemillis();
  
   /** 計算出游戲一次更新的毫秒數 **/
   int difftime = (int) (endtime - starttime);
  
   /** 確保每次更新時間為50幀 **/
   while (difftime <= time_in_frame) {
    difftime = (int) (system.currenttimemillis() - starttime);
    /** 線程等待 **/
    thread.yield();
   }
  
   }
   
 }
 @override
 public void surfacecreated(surfaceholder holder) {
  // todo auto-generated method stub
  mcanvas =surfaceholder.lockcanvas();
  mcanvas.drawbitmap(bg, 0,0, null);
  surfaceholder.unlockcanvasandpost(mcanvas);
   
  misrunning=true;
  new thread(this).start();
 }
 @override
 public void surfacechanged(surfaceholder holder, int format, int width,
   int height) {
  // todo auto-generated method stub
   
 }
 @override
 public void surfacedestroyed(surfaceholder holder) {
  // todo auto-generated method stub
   misrunning = false;
 }
  
  
}

看看運行效果:

Android中SurfaceView和view畫出觸摸軌跡

當我不設置背景時是沒問題的,但使用了背景就不停的閃爍了,不知道有沒同學知道的,可以說一下。

大家可以閱讀本文《解決android surfaceview繪制觸摸軌跡閃爍問題的方法》,或許對大家的學習有所幫助。

五、總結
兩種方式都是可以實現的,而且仔細對比發現surfaceview響應的速度比view快很多,view想必與surfaceview更容易實現。
view用于顯示被動更新的動畫,即需要操作才會更新的動畫,而surfaceview則用于主動更新的動畫,如在界面上顯示一個奔跑的小狗。
view更新界面是在ui主線程。surfaceview是自己起一個線程更新界面。

以上就是本文的全部內容,希望大家喜歡。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久 这里只精品 免费 | 俄罗斯三级在线观看级 | 6080伦理久久精品亚洲 | 日本ssswww大学生 | 成年性香蕉漫画在线观看 | 青草视频久久 | 久久国产热视频99rev6 | 精品在线一区 | 国产色拍 | 国语刺激对白勾搭视频在线观看 | jj视频免费观看 | 日韩制服丝袜在线观看 | 97色伦| 新影音先锋男人色资源网 | 2019天天干夜夜操 | 色综合九九 | 五月色婷婷网在线观看 | 色亚| 手机亚洲第一页 | 亚洲国产欧美日韩在线一区 | 午夜无码片在线观看影院 | 手机跑分排行最新排名 | 99久久精品免费看国产四区 | 国产成人精品日本亚洲网站 | 扒开老师两片湿漉的肉 | 国产做a爰片久久毛片 | 亚洲精品一区二区久久这里 | 精品国语国产在线对白 | 奇米影视在线视频8888 | 免费视频亚洲 | 亚洲欧美日韩在线观看看另类 | 女高h | 成年人视频在线 | 肉宠文很肉到处做1v1 | www射com| 国产精品国产精品国产三级普 | 91天堂素人| 嫩草成人影院 | 四虎影视在线影院在线观看观看 | 91麻豆制片厂| 亚洲高清无码在线 视频 |