Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.util.Log
import android.widget.RemoteViews
import es.antonborri.home_widget.HomeWidgetProvider
Expand Down Expand Up @@ -38,7 +38,7 @@ class BeeCountWidgetProvider : HomeWidgetProvider() {
val file = File(imagePath)
Log.d(TAG, "File exists: ${file.exists()}, size: ${if(file.exists()) file.length() else 0}")

val bitmap = BitmapFactory.decodeFile(imagePath)
val bitmap = loadWidgetBitmap(imagePath)
if (bitmap != null) {
Log.d(TAG, "Bitmap decoded successfully: ${bitmap.width}x${bitmap.height}")
setImageViewBitmap(R.id.widget_image, bitmap)
Expand Down Expand Up @@ -96,4 +96,26 @@ class BeeCountWidgetProvider : HomeWidgetProvider() {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
return intent
}

private fun loadWidgetBitmap(imagePath: String): Bitmap? {
val bounds = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeFile(imagePath, bounds)
if (bounds.outWidth <= 0 || bounds.outHeight <= 0) return null

val maxWidth = 600
val maxHeight = 300
var sampleSize = 1
while (bounds.outWidth / sampleSize > maxWidth ||
bounds.outHeight / sampleSize > maxHeight
) {
sampleSize *= 2
}

val options = BitmapFactory.Options().apply {
inSampleSize = sampleSize
}
return BitmapFactory.decodeFile(imagePath, options)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- widget_background(小部件背景)在夜间模式下自动使用此配色。 -->
<solid android:color="#2C2C2E" />
<corners android:radius="16dp" />
<stroke
Expand Down
17 changes: 8 additions & 9 deletions android/app/src/main/res/layout/beecount_widget.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@drawable/widget_background">

<!--
scaleType=fitCenter:
按 Flutter 渲染图(364x182, 2:1) 的原比例完整显示,不裁减。用户在
桌面把 widget 横向拉宽后,view 宽高比偏离 2:1,fitCenter 会让图片
居中 + 留透明空白(letterbox),而不是像 centerCrop 那样切顶/底
内容。
曾经用过 fitXY(变形拉伸) 和 centerCrop(裁减),前者难看后者切内容,
都不如 fitCenter 直观。
scaleType=fitXY:
Android 各桌面给同一个小部件的实际宽高比并不完全一致。fitCenter
会在小米桌面等偏高的容器里留下上下空白;centerCrop 又会裁掉内容。
这里让渲染图完整填满宿主区域,避免白边或透明占位。
-->
<ImageView
android:id="@+id/widget_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:background="@drawable/widget_background"
android:scaleType="fitXY"
android:contentDescription="Widget content" />

<!-- 透明点击层:左右各半,左侧支出,右侧收入 -->
Expand Down
37 changes: 12 additions & 25 deletions lib/widget/home_widget_view.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:io';
import 'package:flutter/material.dart';

/// Flutter widget that will be rendered as the home screen widget
Expand Down Expand Up @@ -44,32 +43,22 @@ class HomeWidgetView extends StatelessWidget {

@override
Widget build(BuildContext context) {
// For Android, add top/bottom padding to achieve 2:1 ratio (364x182)
// iOS uses natural 364x169 size
final isAndroid = Platform.isAndroid;
final verticalPadding = isAndroid ? (182 - 169) / 2 : 0.0; // 6.5 pixels top and bottom

return Container(
width: width,
height: height,
color: Colors.transparent, // Transparent background for padding area
padding: EdgeInsets.symmetric(vertical: verticalPadding),
child: Container(
width: 364,
height: 169, // Always render content at 364x169
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
themeColor,
Color.lerp(themeColor, Colors.black, 0.15)!,
],
),
borderRadius: BorderRadius.circular(16),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
themeColor,
Color.lerp(themeColor, Colors.black, 0.15)!,
],
),
padding: const EdgeInsets.all(12),
child: Column(
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.all(12),
child: Column(
children: [
// Header
Row(
Expand Down Expand Up @@ -172,7 +161,6 @@ class HomeWidgetView extends StatelessWidget {
),
),
],
),
),
);
}
Expand Down Expand Up @@ -258,5 +246,4 @@ class HomeWidgetView extends StatelessWidget {
),
);
}

}
4 changes: 3 additions & 1 deletion lib/widget/widget_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ class WidgetManager {
),
key: 'widgetImage',
logicalSize: widgetSize,
pixelRatio: 4.0, // @4x for high resolution
// RemoteViews 会通过 Binder 传递位图;过大的 @4x 图在部分小米桌面上会更新失败,
// 表现为小部件占位但透明。1.5x 保持清晰度,同时把位图控制在安全大小内。
pixelRatio: 1.5,
);
print('✅ 小组件渲染完成');

Expand Down