-
Notifications
You must be signed in to change notification settings - Fork 23
/
StickyViewHelper.java
339 lines (302 loc) · 10.6 KB
/
StickyViewHelper.java
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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
package com.mabeijianxi.stickydotslib.view;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.drawable.AnimationDrawable;
import android.support.v4.view.MotionEventCompat;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import com.mabeijianxi.stickydotslib.R;
import com.mabeijianxi.stickydotslib.utils.DisplayUtils;
/**
* Created by mabeijianxi on 2016/1/19.
* StickyView辅助类,让StickyView使用更加简单,起到桥梁的作用
* 也可以更具自己需求复写某些方法
*/
public class StickyViewHelper implements View.OnTouchListener, StickyView.DragStickViewListener {
private int dragViewLayouId;
private Runnable viewInRangeMoveRun;
private Runnable viewOutRangeMoveRun;
private Runnable viewOut2InRangeUpRun;
private Runnable viewOutRangeUpRun;
private Runnable mViewInRangeUpRun;
private WindowManager mWm;
private WindowManager.LayoutParams mParams;
private StickyView mStickyView;
private View mDragView;
private final Context mContext;
private View mShowView;
private int mStatusBarHeight;
private float mMinFixRadius;
private float mFixRadius;
private float mFarthestDistance;
private int mPathColor;
public StickyViewHelper(Context mContext, View mShowView, int dragViewLayouId) {
this.mContext = mContext;
this.mShowView = mShowView;
this.dragViewLayouId=dragViewLayouId;
/**
* 这步比较关键,当触摸到外部小圆点的时候会执行StickyViewHelper实现的onTouch方法
*/
mShowView.setOnTouchListener(this);
mParams = new WindowManager.LayoutParams();
mParams.format = PixelFormat.TRANSLUCENT;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_DOWN) {
ViewParent parent = v.getParent();
if (parent == null) {
return false;
}
parent.requestDisallowInterceptTouchEvent(true);
mStatusBarHeight = DisplayUtils.getStatusBarHeight(mShowView);
mShowView.setVisibility(View.INVISIBLE);
/**
* 当手指触摸小圆点的时候这个对象将被创建,我试过不这样,直接用mShowView,
* 动画做完以后WindowManager执行remove,mShowView再加添回其对应的父布局
* 看着没问题,但是下次再按下这个小圆点就得不到它在屏幕上的坐标,points里面是0,0
* 第一次计算的时候会产生误差。具体原因还在查询。
*/
mDragView = LayoutInflater.from(mContext).inflate(dragViewLayouId, null, false);
// 文本内容复制
copyText();
mWm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mStickyView = new StickyView(mContext, mDragView, mWm);
// 初始化数据
initStickyViewData();
// 注册拖拽过程的监听回调
mStickyView.setDragStickViewListener(this);
// 开始添加的窗体让其显示
mWm.addView(mStickyView, mParams);
mWm.addView(mDragView, mParams);
}
/**
* 当执行完了以上初始操作后把事件交由StickyView处理触摸
*/
mStickyView.onTouchEvent(event);
return true;
}
/**
* 初始化StickyView的
*/
private void initStickyViewData() {
// 计算小圆点在屏幕的坐标
int[] points = new int[2];
mShowView.getLocationInWindow(points);
int x = points[0] + mShowView.getWidth() / 2;
int y = points[1] + mShowView.getHeight() / 2;
// 需要外部设置,当StickyView还没有执行完dispatchAttachedToWindow()时是计算不出其高度的
mStickyView.setStatusBarHeight(mStatusBarHeight);
if(mFarthestDistance>0){
mStickyView.setFarthestDistance(mFarthestDistance);
}
if(mMinFixRadius>0){
mStickyView.setMinFixRadius(mMinFixRadius);
}
if(mFixRadius>0){
mStickyView.setFixRadius(mFixRadius);
}
if(mPathColor!=0){
mStickyView.setPaintColor(mPathColor);
}
// 初始化做作画的圆和控制点坐标
mStickyView.setShowCanterPoint(x, y);
}
/**
* 复制文本内容
*/
private void copyText() {
if(mShowView instanceof TextView &&mDragView instanceof TextView){
((TextView)mDragView).setText((((TextView) mShowView).getText().toString()));
}
}
/**
* 设置最大拖拽范围
* @param mFarthestDistance px
*/
public void setFarthestDistance(float mFarthestDistance) {
this.mFarthestDistance = mFarthestDistance;
}
/**
* 设置拖拽过程中固定圆变化的最小半径值
* @param mMinFixRadius px
*/
public void setMinFixRadius(float mMinFixRadius) {
this.mMinFixRadius = mMinFixRadius;
}
/**
* 设置固定圆半径
* @param mFixRadius px
*/
public void setFixRadius(float mFixRadius) {
this.mFixRadius = mFixRadius;
}
/**
* 设置绘制颜色
* @param mPathColor
*/
public void setmPathColor(int mPathColor) {
this.mPathColor = mPathColor;
}
/**
* 在范围内移动回调
* @param dragCanterPoint 拖拽的中心坐标
*/
@Override
public void inRangeMove(PointF dragCanterPoint) {
if(viewInRangeMoveRun !=null){
viewInRangeMoveRun.run();
}
}
/**
* 在范围外移动回调
* @param dragCanterPoint 拖拽的中心坐标
*/
@Override
public void outRangeMove(PointF dragCanterPoint) {
if(viewOutRangeMoveRun !=null){
viewOutRangeMoveRun.run();
}
}
/**
* 当移出了规定范围,最后在范围内松手的回调
* @param dragCanterPoint
*/
@Override
public void out2InRangeUp(PointF dragCanterPoint) {
removeView();
if(viewOut2InRangeUpRun !=null){
viewOut2InRangeUpRun.run();
}
}
/**
* 当移出了规定范围,最后在范围外松手的回调
* @param dragCanterPoint
*/
@Override
public void outRangeUp(PointF dragCanterPoint) {
removeView();
playAnim(dragCanterPoint);
}
/**
* 一直没有移动出范围,在范围内松手的回调
* @param dragCanterPoint
*/
@Override
public void inRangeUp(PointF dragCanterPoint) {
removeView();
if(mViewInRangeUpRun !=null){
mViewInRangeUpRun.run();
}
}
/**
* 播放移除动画(帧动画),这个过程根据个人喜好
* @param dragCanterPoint
*/
private void playAnim(PointF dragCanterPoint) {
final ImageView imageView = new ImageView(mContext);
imageView.setImageResource(R.drawable.out_anim);
final AnimationDrawable mAnimDrawable = (AnimationDrawable) imageView
.getDrawable();
mParams.gravity= Gravity.TOP|Gravity.LEFT;
// 这里得到的是其真实的大小,因为此时还得不到其测量值
int intrinsicWidth = imageView.getDrawable().getIntrinsicWidth();
int intrinsicHeight = imageView.getDrawable().getIntrinsicHeight();
mParams.x= (int) dragCanterPoint.x-intrinsicWidth/2;
mParams.y= (int) dragCanterPoint.y-intrinsicHeight/2-mStatusBarHeight;
mParams.width=WindowManager.LayoutParams.WRAP_CONTENT;
mParams.height=WindowManager.LayoutParams.WRAP_CONTENT;
// 获取播放一次帧动画的总时长
long duration = getAnimDuration(mAnimDrawable);
mWm.addView(imageView, mParams);
mAnimDrawable.start();
// 由于帧动画不能定时停止,只能采用这种办法
imageView.postDelayed(new Runnable() {
@Override
public void run() {
mAnimDrawable.stop();
imageView.clearAnimation();
mWm.removeView(imageView);
if (viewOutRangeUpRun != null) {
viewOutRangeUpRun.run();
}
}
},duration);
}
/**
* 得到帧动画的摧毁时间
* @param mAnimDrawable
* @return
*/
private long getAnimDuration(AnimationDrawable mAnimDrawable) {
long duration=0;
for(int i=0;i<mAnimDrawable.getNumberOfFrames();i++){
duration += mAnimDrawable.getDuration(i);
}
return duration;
}
private void removeView() {
if (mWm != null && mStickyView.getParent() != null && mDragView.getParent() != null) {
mWm.removeView(mStickyView);
mWm.removeView(mDragView);
}
}
public Runnable getViewInRangeMoveRun() {
return viewInRangeMoveRun;
}
public Runnable getViewOutRangeMoveRun() {
return viewOutRangeMoveRun;
}
public Runnable getViewOut2InRangeUpRun() {
return viewOut2InRangeUpRun;
}
/**
* view在范围内移动指此此Runnable
* @param viewInRangeMoveRun
*/
public void setViewInRangeMoveRun(Runnable viewInRangeMoveRun) {
this.viewInRangeMoveRun = viewInRangeMoveRun;
}
/**
* view在范围外移动执行此Runnable
* @param viewOutRangeMoveRun
*/
public void setViewOutRangeMoveRun(Runnable viewOutRangeMoveRun) {
this.viewOutRangeMoveRun = viewOutRangeMoveRun;
}
/**
* view移出过范围,最后在范围内松手执行次Runnable
* @param viewOut2InRangeUpRun
*/
public void setViewOut2InRangeUpRun(Runnable viewOut2InRangeUpRun) {
this.viewOut2InRangeUpRun = viewOut2InRangeUpRun;
}
/**
* view没有移出过范围,在范围内松手
* @param mViewInRangeUpRun
*/
public void setViewInRangeUpRun(Runnable mViewInRangeUpRun) {
this.mViewInRangeUpRun = mViewInRangeUpRun;
}
/**
* view移出范围,最后在范围外松手
* @param viewOutRangeUpRun
*/
public void setViewOutRangeUpRun(Runnable viewOutRangeUpRun) {
this.viewOutRangeUpRun = viewOutRangeUpRun;
}
public Runnable getViewOutRangeUpRun() {
return viewOutRangeUpRun;
}
public Runnable getmViewInRangeUpRun() {
return mViewInRangeUpRun;
}
}