99
1010public final class BlurEngine {
1111 public static BlurController controller = new BlurController ();
12+
13+ // volatile để đảm bảo tính nhất quán dữ liệu giữa Thread của Controller và UI Thread
1214 public static volatile Bitmap blurBitmap ;
1315 public static boolean isPaused = true ;
1416
@@ -39,41 +41,32 @@ public void setup() {
3941 }
4042
4143 public Bitmap getUpdatedBlurBitmap () {
42- // 1. Kiểm tra an toàn: Bitmap phải tồn tại và View phải có kích thước
44+ // Kiểm tra an toàn Bitmap trước khi xử lý
4345 if (isPaused || blurBitmap == null || blurBitmap .isRecycled () ||
4446 targetView .getWidth () <= 0 || targetView .getHeight () <= 0 ) {
4547 return null ;
4648 }
4749
48- // 2. Lấy vị trí CHÍNH XÁC của View trên màn hình ngay tại thời điểm vẽ
49- targetView .getLocationOnScreen (location );
50+ targetView .getLocationInWindow (location );
5051
51- // 3. Lấy kích thước toàn màn hình (hoặc root view) để tính tỷ lệ
5252 View rootView = targetView .getRootView ();
53- int rootWidth = rootView .getWidth ();
54- int rootHeight = rootView .getHeight ();
55-
56- if (rootWidth <= 0 || rootHeight <= 0 ) return null ;
53+ // Tính toán tỷ lệ dựa trên kích thước thực tế của bitmap (đã được scale nhỏ ở Controller)
54+ float scaleX = (float ) blurBitmap .getWidth () / rootView .getWidth ();
55+ float scaleY = (float ) blurBitmap .getHeight () / rootView .getHeight ();
5756
58- // 4. Tính toán tỷ lệ giữa ảnh blur đã scale và màn hình thực tế
59- float scaleX = (float ) blurBitmap .getWidth () / rootWidth ;
60- float scaleY = (float ) blurBitmap .getHeight () / rootHeight ;
57+ int x = (int ) (location [0 ] * scaleX );
58+ int y = (int ) (location [1 ] * scaleY );
59+ int w = (int ) (targetView .getWidth () * scaleX );
60+ int h = (int ) (targetView .getHeight () * scaleY );
6161
62- // 5. Tính toán tọa độ vùng cắt trên ảnh blur
63- // Cần dùng float để tránh sai số tích lũy khi vuốt nhanh, sau đó mới ép kiểu int
64- int x = Math .round (location [0 ] * scaleX );
65- int y = Math .round (location [1 ] * scaleY );
66- int w = Math .round (targetView .getWidth () * scaleX );
67- int h = Math .round (targetView .getHeight () * scaleY );
68-
69- // 6. Ràng buộc tọa độ để không cắt ra ngoài phạm vi bitmap
62+ // Giới hạn vùng cắt bên trong phạm vi Bitmap
7063 x = Math .max (0 , Math .min (x , blurBitmap .getWidth () - w ));
7164 y = Math .max (0 , Math .min (y , blurBitmap .getHeight () - h ));
7265
7366 if (w > 0 && h > 0 ) {
7467 try {
75- // Tối ưu bộ nhớ: Chỉ tạo lại bitmap đệm khi kích thước view thay đổi
7668 if (cachedBitmap == null || cachedBitmap .getWidth () != w || cachedBitmap .getHeight () != h ) {
69+ // Giải phóng cached cũ nếu kích thước thay đổi
7770 if (cachedBitmap != null ) cachedBitmap .recycle ();
7871 cachedBitmap = Bitmap .createBitmap (w , h , Bitmap .Config .ARGB_8888 );
7972 cachedCanvas = new Canvas (cachedBitmap );
@@ -82,12 +75,8 @@ public Bitmap getUpdatedBlurBitmap() {
8275 srcRect .set (x , y , x + w , y + h );
8376 cachedCanvas .drawColor (0 , PorterDuff .Mode .CLEAR );
8477
85- // Vẽ vùng ảnh tương ứng từ ảnh nền vào cache
8678 cachedCanvas .drawBitmap (blurBitmap , srcRect , new Rect (0 , 0 , w , h ), null );
87-
88- // Nhuộm màu (Tint) để tạo hiệu ứng kính mờ (Frost Glass)
8979 cachedCanvas .drawColor (getBlurTintColor ());
90-
9180 return cachedBitmap ;
9281 } catch (Exception e ) {
9382 return null ;
@@ -108,11 +97,14 @@ public static Paint getStrokePaint(Context context) {
10897 strokePaint .setStyle (Paint .Style .STROKE );
10998 strokePaint .setStrokeWidth (3.0f );
11099 }
100+
111101 int colorRes = ThemeModeState .isDarkMode () ? R .color .colorPirmLight : R .color .colorPirmDark ;
112102 int color = ContextCompat .getColor (context , colorRes );
103+
113104 if (strokePaint .getColor () != color ) {
114105 strokePaint .setColor (color );
115106 }
107+
116108 return strokePaint ;
117109 }
118110
0 commit comments