-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathXPopupUtils.java
More file actions
623 lines (581 loc) · 25.1 KB
/
Copy pathXPopupUtils.java
File metadata and controls
623 lines (581 loc) · 25.1 KB
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
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
package com.lxj.xpopup.util;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.OvershootInterpolator;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.FloatRange;
import com.lxj.xpopup.core.AttachPopupView;
import com.lxj.xpopup.core.BasePopupView;
import com.lxj.xpopup.core.BottomPopupView;
import com.lxj.xpopup.core.CenterPopupView;
import com.lxj.xpopup.core.DrawerPopupView;
import com.lxj.xpopup.core.PositionPopupView;
import com.lxj.xpopup.enums.ImageType;
import com.lxj.xpopup.impl.FullScreenPopupView;
import com.lxj.xpopup.impl.PartShadowPopupView;
import com.lxj.xpopup.interfaces.XPopupImageLoader;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description:
* Create by lxj, at 2018/12/7
*/
public class XPopupUtils {
public static int getWindowWidth(Context context) {
return ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
}
//应用界面可见高度,可能不包含导航和状态栏,看Rom实现
public static int getAppHeight(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (wm == null) return -1;
Point point = new Point();
wm.getDefaultDisplay().getSize(point);
return point.y;
}
//屏幕的高度,包含状态栏,导航栏,看Rom实现
public static int getScreenHeight(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (wm == null) return -1;
Point point = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
wm.getDefaultDisplay().getRealSize(point);
} else {
wm.getDefaultDisplay().getSize(point);
}
return point.y;
}
public static int dp2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
public static int getStatusBarHeight() {
Resources resources = Resources.getSystem();
int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
return resources.getDimensionPixelSize(resourceId);
}
/**
* Return the navigation bar's height.
*
* @return the navigation bar's height
*/
public static int getNavBarHeight() {
Resources res = Resources.getSystem();
int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId != 0) {
return res.getDimensionPixelSize(resourceId);
} else {
return 0;
}
}
public static void setWidthHeight(View target, int width, int height) {
if (width <= 0 && height <= 0) return;
ViewGroup.LayoutParams params = target.getLayoutParams();
if (width > 0) params.width = width;
if (height > 0) params.height = height;
target.setLayoutParams(params);
}
public static void applyPopupSize(final ViewGroup content, final int maxWidth, final int maxHeight,
final int popupWidth, final int popupHeight, final Runnable afterApplySize) {
content.post(new Runnable() {
@Override
public void run() {
ViewGroup.LayoutParams params = content.getLayoutParams();
View implView = content.getChildAt(0);
ViewGroup.LayoutParams implParams = implView.getLayoutParams();
// 假设默认Content宽是match,高是wrap
int w = content.getMeasuredWidth();
// response impl view wrap_content params.
if (maxWidth > 0) {
//指定了最大宽度,就限制最大宽度
params.width = Math.min(w, maxWidth);
if (popupWidth > 0) {
params.width = Math.min(popupWidth, maxWidth);
implParams.width = Math.min(popupWidth, maxWidth);
}
} else if (popupWidth > 0) {
params.width = popupWidth;
implParams.width = popupWidth;
}
int h = content.getMeasuredHeight();
if (maxHeight > 0) {
params.height = Math.min(h, maxHeight);
if (popupHeight > 0) {
params.height = Math.min(popupHeight, maxHeight);
implParams.height = Math.min(popupHeight, maxHeight);
}
} else if(popupHeight > 0) {
params.height = popupHeight;
implParams.height = popupHeight;
}
implView.setLayoutParams(implParams);
content.setLayoutParams(params);
content.post(new Runnable() {
@Override
public void run() {
if (afterApplySize != null) {
afterApplySize.run();
}
}
});
}
});
}
public static void setCursorDrawableColor(EditText et, int color) {
//暂时没有找到有效的方法来动态设置cursor的颜色
}
public static BitmapDrawable createBitmapDrawable(Resources resources, int width, int color) {
Bitmap bitmap = Bitmap.createBitmap(width, 20, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setColor(color);
canvas.drawRect(0, 0, bitmap.getWidth(), 4, paint);
paint.setColor(Color.TRANSPARENT);
canvas.drawRect(0, 4, bitmap.getWidth(), 20, paint);
BitmapDrawable bitmapDrawable = new BitmapDrawable(resources, bitmap);
bitmapDrawable.setGravity(Gravity.BOTTOM);
return bitmapDrawable;
}
public static StateListDrawable createSelector(Drawable defaultDrawable, Drawable focusDrawable) {
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_focused}, focusDrawable);
stateListDrawable.addState(new int[]{}, defaultDrawable);
return stateListDrawable;
}
public static boolean isInRect(float x, float y, Rect rect) {
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
}
private static int sDecorViewDelta = 0;
public static int getDecorViewInvisibleHeight(final Window window) {
final View decorView = window.getDecorView();
final Rect outRect = new Rect();
decorView.getWindowVisibleDisplayFrame(outRect);
int delta = Math.abs(decorView.getBottom() - outRect.bottom);
if (delta <= getNavBarHeight()) {
sDecorViewDelta = delta;
return 0;
}
return delta - sDecorViewDelta;
}
//监听到的keyboardHeight有一定几率是错误的,比如在同时显示导航栏和弹出输入法的时候,有一定几率会算上导航栏的高度,
//这个不是必现的,暂时无解
//为了方便用户修改键盘高度和获取当前键盘高度
static int correctKeyboardHeight = 0;
public static void moveUpToKeyboard(final int keyboardHeight, final BasePopupView pv) {
if (correctKeyboardHeight == 0) correctKeyboardHeight = keyboardHeight;
else if (keyboardHeight != 0)
correctKeyboardHeight = Math.min(correctKeyboardHeight, keyboardHeight);
pv.post(new Runnable() {
@Override
public void run() {
moveUpToKeyboardInternal(correctKeyboardHeight, pv);
}
});
}
//如果变化键盘高度,需要调整弹窗,请使用SimpleCallback,重写onKeyBoardStateChanged,在onKeyBoardStateChanged中调用XPopupUtils.moveUpToKeyboardNow
//或者重写popupView中的onKeyboardHeightChanged
//此处修改correctKeyboardHeight是为了修复打开其他弹窗时键盘高度不对导致遮挡输入框问题
public static void moveUpToKeyboardNow(final int keyboardHeight, final BasePopupView pv) {
correctKeyboardHeight = keyboardHeight;
pv.getPopupContentView().animate().translationY(-keyboardHeight)
.setDuration(200)
.setInterpolator(new OvershootInterpolator(0))
.start();
}
private static void moveUpToKeyboardInternal(int keyboardHeight, BasePopupView pv) {
if (pv.popupInfo == null || !pv.popupInfo.isMoveUpToKeyboard) return;
//暂时忽略PartShadow弹窗和AttachPopupView
if (pv instanceof PositionPopupView || (pv instanceof AttachPopupView && !(pv instanceof PartShadowPopupView))) {
return;
}
//判断是否盖住输入框
ArrayList<EditText> allEts = new ArrayList<>();
findAllEditText(allEts, pv);
EditText focusEt = null;
for (EditText et : allEts) {
if (et.isFocused()) {
focusEt = et;
break;
}
}
int dy = 0;
int popupHeight = pv.getPopupContentView().getHeight();
int popupWidth = pv.getPopupContentView().getWidth();
if (pv.getPopupImplView() != null) {
popupHeight = Math.min(popupHeight, pv.getPopupImplView().getMeasuredHeight());
popupWidth = Math.min(popupWidth, pv.getPopupImplView().getMeasuredWidth());
}
int screenHeight = pv.getMeasuredHeight();
int focusEtTop = 0;
int focusBottom = 0;
if (focusEt != null) {
int[] locations = new int[2];
focusEt.getLocationInWindow(locations);
focusEtTop = locations[1];
focusBottom = focusEtTop + focusEt.getMeasuredHeight();
}
//执行上移
if (pv instanceof FullScreenPopupView ||
(popupWidth == XPopupUtils.getWindowWidth(pv.getContext()) &&
popupHeight == screenHeight)
) {
// 如果是全屏弹窗,特殊处理,只要输入框没被盖住,就不移动。
if (focusBottom + keyboardHeight < screenHeight) {
return;
}
}
if (pv instanceof FullScreenPopupView) {
int overflowHeight = focusBottom + keyboardHeight - screenHeight;
if (focusEt != null && overflowHeight > 0) {
dy = overflowHeight;
}
} else if (pv instanceof CenterPopupView) {
int popupBottom = (screenHeight + popupHeight) / 2;
int targetY = popupBottom + keyboardHeight - screenHeight;
if (focusEt != null && focusEtTop - targetY < 0) {
targetY += focusEtTop - targetY - getStatusBarHeight();//限制不能被状态栏遮住
}
dy = Math.max(0, targetY);
} else if (pv instanceof BottomPopupView) {
dy = keyboardHeight;
if (focusEt != null && focusEtTop - dy < 0) {
dy += focusEtTop - dy - getStatusBarHeight();//限制不能被状态栏遮住
}
} else if (isBottomPartShadow(pv) || pv instanceof DrawerPopupView) {
int overflowHeight = (focusBottom + keyboardHeight) - screenHeight;
if (focusEt != null && overflowHeight > 0) {
dy = overflowHeight;
}
} else if (isTopPartShadow(pv)) {
int overflowHeight = (focusBottom + keyboardHeight) - screenHeight;
if (focusEt != null && overflowHeight > 0) {
dy = overflowHeight;
}
if (dy != 0) {
pv.getPopupImplView().animate().translationY(-dy)
.setDuration(200)
.setInterpolator(new OvershootInterpolator(0))
.start();
}
return;
}
//dy=0说明没有触发移动,有些弹窗有translationY,不能影响它们
if (dy == 0 && pv.getPopupContentView().getTranslationY() != 0) return;
pv.getPopupContentView().animate().translationY(-dy)
.setDuration(200)
.setInterpolator(new OvershootInterpolator(0))
.start();
}
/**
* app可用高度是否包含状态栏的高度
*
* @param context
* @return
*/
private static boolean isAppHeightContainStatusBar(Context context) {
int appHeight = getAppHeight(context);
int screenHeight = getScreenHeight(context);
int statusBarHeight = getStatusBarHeight();
int navHeight = getNavBarHeight();
if (screenHeight == (appHeight + statusBarHeight) ||
screenHeight == (appHeight + navHeight + statusBarHeight)) return false;
return true;
}
private static boolean isBottomPartShadow(BasePopupView pv) {
return pv instanceof PartShadowPopupView && ((PartShadowPopupView) pv).isShowUp;
}
private static boolean isTopPartShadow(BasePopupView pv) {
return pv instanceof PartShadowPopupView && !((PartShadowPopupView) pv).isShowUp;
}
// public static HashMap
public static void moveDown(BasePopupView pv) {
//暂时忽略PartShadow弹窗和AttachPopupView
if (pv instanceof PositionPopupView) return;
if (!(pv instanceof PartShadowPopupView) && pv instanceof AttachPopupView) return;
if (pv instanceof PartShadowPopupView && !isBottomPartShadow(pv)) {
pv.getPopupImplView().animate().translationY(0)
.setDuration(100).start();
} else {
pv.getPopupContentView().animate().translationY(0)
.setDuration(100).start();
}
}
public static boolean isNavBarVisible(Window window) {
boolean isVisible = false;
ViewGroup decorView = (ViewGroup) window.getDecorView();
for (int i = 0, count = decorView.getChildCount(); i < count; i++) {
final View child = decorView.getChildAt(i);
final int id = child.getId();
if (id != View.NO_ID) {
String resourceEntryName = decorView.getContext()
.getResources()
.getResourceEntryName(id);
if ("navigationBarBackground".equals(resourceEntryName)
&& child.getVisibility() == View.VISIBLE) {
isVisible = true;
break;
}
}
}
if (isVisible) {
int visibility = decorView.getSystemUiVisibility();
isVisible = (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
}
return isVisible;
}
public static void findAllEditText(ArrayList<EditText> list, ViewGroup group) {
for (int i = 0; i < group.getChildCount(); i++) {
View v = group.getChildAt(i);
if (v instanceof EditText && v.getVisibility() == View.VISIBLE) {
list.add((EditText) v);
} else if (v instanceof ViewGroup) {
findAllEditText(list, (ViewGroup) v);
}
}
}
public static void saveBmpToAlbum(final Context context, final XPopupImageLoader imageLoader, final Object uri) {
final Handler mainHandler = new Handler(Looper.getMainLooper());
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
@Override
public void run() {
File source = imageLoader.getImageFile(context, uri);
if (source == null) {
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "图片不存在!", Toast.LENGTH_SHORT).show();
}
});
return;
}
//1. create path
String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + Environment.DIRECTORY_PICTURES;
File dirFile = new File(dirPath);
if (!dirFile.exists()) dirFile.mkdirs();
try {
ImageType type = ImageHeaderParser.getImageType(new FileInputStream(source));
String ext = getFileExt(type);
final File target = new File(dirPath, System.currentTimeMillis() + "." + ext);
if (target.exists()) target.delete();
target.createNewFile();
//2. save
writeFileFromIS(target, new FileInputStream(source));
//3. notify
MediaScannerConnection.scanFile(context, new String[]{target.getAbsolutePath()},
new String[]{"image/" + ext}, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(final String path, Uri uri) {
mainHandler.post(new Runnable() {
@Override
public void run() {
if (context != null) {
Toast.makeText(context, "已保存到相册!", Toast.LENGTH_SHORT).show();
}
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
mainHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "没有保存权限,保存功能无法使用!", Toast.LENGTH_SHORT).show();
}
});
}
}
});
}
private static String getFileExt(ImageType type) {
switch (type) {
case GIF:
return "gif";
case PNG:
case PNG_A:
return "png";
case WEBP:
case WEBP_A:
return "webp";
case JPEG:
return "jpeg";
}
return "jpeg";
}
private static boolean writeFileFromIS(final File file, final InputStream is) {
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(file));
byte data[] = new byte[8192];
int len;
while ((len = is.read(data, 0, 8192)) != -1) {
os.write(data, 0, len);
}
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//获取应用可用的屏幕高度
// public static int getPhoneScreenHeight(Window window) {
// DisplayMetrics outMetrics = new DisplayMetrics();
// window.getWindowManager().getDefaultDisplay().getRealMetrics(outMetrics);
// return outMetrics.heightPixels;
// }
public static Bitmap renderScriptBlur(Context context, final Bitmap src,
@FloatRange(
from = 0, to = 25, fromInclusive = false
) final float radius,
final boolean recycle) {
RenderScript rs = null;
Bitmap ret = recycle ? src : src.copy(src.getConfig(), true);
try {
rs = RenderScript.create(context);
rs.setMessageHandler(new RenderScript.RSMessageHandler());
Allocation input = Allocation.createFromBitmap(rs,
ret,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
Allocation output = Allocation.createTyped(rs, input.getType());
ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
blurScript.setInput(input);
blurScript.setRadius(radius);
blurScript.forEach(output);
output.copyTo(ret);
} finally {
if (rs != null) {
rs.destroy();
}
}
return ret;
}
/**
* View to bitmap.
*
* @param view The view.
* @return bitmap
*/
public static Bitmap view2Bitmap(final View view) {
if (view == null) return null;
boolean drawingCacheEnabled = view.isDrawingCacheEnabled();
boolean willNotCacheDrawing = view.willNotCacheDrawing();
view.setDrawingCacheEnabled(true);
view.setWillNotCacheDrawing(false);
Bitmap drawingCache = view.getDrawingCache();
Bitmap bitmap;
if (null == drawingCache) {
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.buildDrawingCache();
drawingCache = view.getDrawingCache();
if (drawingCache != null) {
bitmap = Bitmap.createBitmap(drawingCache);
} else {
bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
}
} else {
bitmap = Bitmap.createBitmap(drawingCache);
}
view.destroyDrawingCache();
view.setWillNotCacheDrawing(willNotCacheDrawing);
view.setDrawingCacheEnabled(drawingCacheEnabled);
return bitmap;
}
public static boolean isLayoutRtl(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Locale primaryLocale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
primaryLocale = context.getResources().getConfiguration().getLocales().get(0);
} else {
primaryLocale = context.getResources().getConfiguration().locale;
}
return TextUtils.getLayoutDirectionFromLocale(primaryLocale) == View.LAYOUT_DIRECTION_RTL;
}
return false;
}
public static Activity context2Activity(View view) {
Context context = view.getContext();
while (context instanceof ContextWrapper) {
if (context instanceof Activity) {
return ((Activity) context);
} else {
context = ((ContextWrapper) context).getBaseContext();
}
}
return null;
}
public static Drawable createDrawable(int color, float radius) {
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.RECTANGLE);
drawable.setColor(color);
drawable.setCornerRadius(radius);
return drawable;
}
public static Drawable createDrawable(int color, float tlRadius, float trRadius, float brRadius,
float blRadius) {
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.RECTANGLE);
drawable.setColor(color);
drawable.setCornerRadii(new float[]{
tlRadius, tlRadius,
trRadius, trRadius,
brRadius, brRadius,
blRadius, blRadius});
return drawable;
}
}