6249d5b2ea
根因:主题 inputDecorationTheme 设了 filled:true/fillColor:bg,自定义容器里嵌 TextField 时内层自铺 bg 底,与容器底色(搜索框 bgSubtle / 登录 surface)不一致 → 两端一色中间另一色接缝(节点搜索框最明显,登录/兑换框也有隐患)。 - kBareInput 加 filled:false:内层 TextField 不再自铺底,底色统一交给外层容器。 - 新增 widgets/pangolin_field.dart:PangolinFieldBox(圆角容器 + 底色 + 可选描边/ 聚焦光环 + 标签 + 前置图标 + 后置 widget)+ bareInputDecoration() 助手。 - 三处输入框统一改用:节点搜索框、登录/注册字段(_field)、兑换码输入框。 - 重生成 auth_login(dark/light)+ desktop_redeem golden(均人工核对外观正确)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
89 lines
3.0 KiB
Dart
89 lines
3.0 KiB
Dart
// pangolin_field.dart — 统一输入框容器组件。
|
|
//
|
|
// 圆角容器(底色 + 可选描边/聚焦光环 + 可选上方标签 + 前置图标 + 后置 widget),
|
|
// 内层放一个用 [bareInputDecoration] 的 TextField。底色由本容器统一提供,内层不再
|
|
// 自铺填充 → 杜绝「容器底色 ≠ TextField filled 底色」的两端一色中间另一色接缝。
|
|
// 聚焦态(accent 边 + 光环)也由容器负责。搜索框/兑换码/登录注册输入框共用此组件。
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../pangolin_theme.dart';
|
|
|
|
/// 内层 TextField 用的「裸」装饰:无边框、无填充。底色/边框/聚焦都交给 [PangolinFieldBox]。
|
|
InputDecoration bareInputDecoration({
|
|
EdgeInsetsGeometry contentPadding = const EdgeInsets.symmetric(vertical: 12),
|
|
String? hintText,
|
|
TextStyle? hintStyle,
|
|
String? counterText,
|
|
}) =>
|
|
kBareInput.copyWith(
|
|
contentPadding: contentPadding,
|
|
hintText: hintText,
|
|
hintStyle: hintStyle,
|
|
counterText: counterText,
|
|
);
|
|
|
|
class PangolinFieldBox extends StatelessWidget {
|
|
const PangolinFieldBox({
|
|
super.key,
|
|
required this.child,
|
|
this.fill,
|
|
this.label,
|
|
this.leading,
|
|
this.trailing,
|
|
this.focused = false,
|
|
this.bordered = true,
|
|
this.horizontalPadding = 14,
|
|
});
|
|
|
|
/// 内层输入(用 [bareInputDecoration] 构造装饰)。
|
|
final Widget child;
|
|
|
|
/// 容器底色;默认 [PangolinScheme.surface]。搜索框传 bgSubtle、兑换码传 bg。
|
|
final Color? fill;
|
|
|
|
/// 上方标签(可空)。登录/注册字段用。
|
|
final String? label;
|
|
|
|
/// 前置图标(可空)。
|
|
final IconData? leading;
|
|
|
|
/// 后置 widget(可空):如密码显示切换、发送验证码。
|
|
final Widget? trailing;
|
|
|
|
/// 聚焦态:accent 边 + 光环(仅 [bordered] 时生效)。
|
|
final bool focused;
|
|
|
|
/// 是否描边。搜索框传 false(只有底色,无边)。
|
|
final bool bordered;
|
|
|
|
final double horizontalPadding;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final c = context.pangolin;
|
|
final box = AnimatedContainer(
|
|
duration: const Duration(milliseconds: 160),
|
|
padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
|
|
decoration: BoxDecoration(
|
|
color: fill ?? c.surface,
|
|
borderRadius: BorderRadius.circular(PangolinRadius.md),
|
|
border: bordered
|
|
? Border.all(color: focused ? c.accent : c.borderStrong, width: 1.5)
|
|
: null,
|
|
boxShadow: (bordered && focused) ? [BoxShadow(color: c.ring, spreadRadius: 3)] : null,
|
|
),
|
|
child: Row(children: [
|
|
if (leading != null) ...[Icon(leading, size: 18, color: c.fg3), const SizedBox(width: 10)],
|
|
Expanded(child: child),
|
|
if (trailing != null) trailing!,
|
|
]),
|
|
);
|
|
if (label == null) return box;
|
|
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
|
Text(label!, style: PangolinText.caption.copyWith(color: c.fg2, fontWeight: FontWeight.w600)),
|
|
const SizedBox(height: 7),
|
|
box,
|
|
]);
|
|
}
|
|
}
|