Some checks failed
Build Android APK / 编译 libcore.aar (push) Has been cancelled
Build Android APK / 编译 Android APK (release) (push) Has been cancelled
Build Android APK / 创建 GitHub Release (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Android) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Windows) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (macOS) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Linux) (push) Has been cancelled
Build Multi-Platform / 构建 Android APK (push) Has been cancelled
Build Multi-Platform / 构建 Windows (push) Has been cancelled
Build Multi-Platform / 构建 macOS (push) Has been cancelled
Build Multi-Platform / 构建 Linux (push) Has been cancelled
Build Multi-Platform / 创建 Release (push) Has been cancelled
Build Windows / build (push) Has been cancelled
115 lines
3.2 KiB
Dart
115 lines
3.2 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
|
||
class HiFixedScrollbar extends StatefulWidget {
|
||
final Widget child;
|
||
final ScrollController controller;
|
||
|
||
final bool isShowScrollbar;
|
||
|
||
/// 距离右边的间距(默认 18)
|
||
final double right;
|
||
/// 滚动条宽度
|
||
final double thickness;
|
||
/// 滚动条颜色(默认白色 30%)
|
||
final Color thumbColor;
|
||
/// 背景轨道颜色(默认白色 15%)
|
||
final Color trackColor;
|
||
/// 滚动条固定高度(默认 50)
|
||
final double thumbHeight;
|
||
|
||
const HiFixedScrollbar({
|
||
super.key,
|
||
required this.child,
|
||
required this.controller,
|
||
this.right = 18,
|
||
this.isShowScrollbar = true,
|
||
this.thickness = 5,
|
||
this.thumbHeight = 50,
|
||
this.thumbColor = const Color.fromRGBO(255, 255, 255, 0.3),
|
||
this.trackColor = const Color.fromRGBO(255, 255, 255, 0.15),
|
||
});
|
||
|
||
@override
|
||
State<HiFixedScrollbar> createState() => _HiFixedScrollbarState();
|
||
}
|
||
|
||
class _HiFixedScrollbarState extends State<HiFixedScrollbar> {
|
||
double _thumbOffset = 0.0;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
widget.controller.addListener(_updateThumbPosition);
|
||
}
|
||
|
||
void _updateThumbPosition() {
|
||
if (!mounted) return;
|
||
final position = widget.controller.position;
|
||
if (!position.hasPixels || !position.hasContentDimensions) return;
|
||
|
||
final maxScrollExtent = position.maxScrollExtent;
|
||
final offset = position.pixels;
|
||
final viewport = position.viewportDimension;
|
||
|
||
// ✅ 固定高度滚动条,只根据滚动比例移动位置
|
||
final trackHeight = viewport - widget.thumbHeight;
|
||
final scrollRatio = maxScrollExtent == 0 ? 0 : offset / maxScrollExtent;
|
||
|
||
setState(() {
|
||
_thumbOffset = (trackHeight * scrollRatio).clamp(0, trackHeight);
|
||
});
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
widget.controller.removeListener(_updateThumbPosition);
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return LayoutBuilder(
|
||
builder: (_, constraints) {
|
||
return Stack(
|
||
children: [
|
||
// 滚动内容
|
||
widget.child,
|
||
|
||
if(widget.isShowScrollbar)
|
||
...[
|
||
// 滚动条轨道
|
||
Positioned(
|
||
right: widget.right.w,
|
||
top: 0,
|
||
bottom: 0,
|
||
child: Container(
|
||
width: widget.thickness.w,
|
||
decoration: BoxDecoration(
|
||
color: widget.trackColor,
|
||
borderRadius: BorderRadius.circular(4),
|
||
),
|
||
),
|
||
),
|
||
|
||
// 滚动条拇指
|
||
Positioned(
|
||
right: widget.right.w,
|
||
top: _thumbOffset,
|
||
child: Container(
|
||
width: widget.thickness.w,
|
||
height: widget.thumbHeight,
|
||
decoration: BoxDecoration(
|
||
color: widget.thumbColor,
|
||
borderRadius: BorderRadius.circular(4),
|
||
),
|
||
),
|
||
),
|
||
]
|
||
],
|
||
);
|
||
},
|
||
);
|
||
}
|
||
}
|