webdav存在自引用问题,现版本修复完成
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 磁吸进度状态
|
||||
class MagneticSnapState {
|
||||
/// 吸附进度 0.0 ~ 1.0
|
||||
final double progress;
|
||||
|
||||
/// 媒体库透明度
|
||||
double get mediaOpacity {
|
||||
// 0% ~ 70%: 1.0 → 0.45
|
||||
// 70% ~ 100%: 0.45 → 0
|
||||
if (progress <= 0.7) {
|
||||
return 1.0 - (progress / 0.7) * 0.55;
|
||||
} else {
|
||||
final t = (progress - 0.7) / 0.3;
|
||||
return 0.45 * (1 - t);
|
||||
}
|
||||
}
|
||||
|
||||
/// 收藏标题位移(从 +12px → 0)
|
||||
double get favoriteTranslateY {
|
||||
return (1 - progress) * 12;
|
||||
}
|
||||
|
||||
/// 收藏列表展开程度 0.0 ~ 1.0
|
||||
double get listReveal {
|
||||
if (progress <= 0.7) return 0.0;
|
||||
return (progress - 0.7) / 0.3;
|
||||
}
|
||||
|
||||
/// 是否完全吸附
|
||||
bool get isSnapped => progress >= 1.0;
|
||||
|
||||
/// 是否在磁吸区(进度 > 70%)
|
||||
bool get isInMagneticZone => progress > 0.7;
|
||||
|
||||
const MagneticSnapState(this.progress);
|
||||
|
||||
factory MagneticSnapState.initial() => const MagneticSnapState(0.0);
|
||||
|
||||
MagneticSnapState copyWith({double? progress}) {
|
||||
return MagneticSnapState(progress ?? this.progress);
|
||||
}
|
||||
}
|
||||
|
||||
/// 磁吸控制器
|
||||
class MagneticScrollController extends ChangeNotifier {
|
||||
/// 吸附进度
|
||||
double _progress = 0.0;
|
||||
double get progress => _progress;
|
||||
|
||||
/// 是否已吸附
|
||||
bool _isSnapped = false;
|
||||
bool get isSnapped => _isSnapped;
|
||||
|
||||
/// 动画控制器(用于吸附动画)
|
||||
AnimationController? _animationController;
|
||||
TickerProvider? _tickerProvider;
|
||||
|
||||
/// 状态
|
||||
MagneticSnapState get state => MagneticSnapState(_progress);
|
||||
|
||||
void init(TickerProvider vsync) {
|
||||
_animationController = AnimationController(
|
||||
vsync: vsync,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/// 更新滚动进度(在滚动时调用)
|
||||
void updateProgress(double newProgress) {
|
||||
if (_isSnapped) return;
|
||||
_progress = newProgress.clamp(0.0, 1.0);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// 处理松手事件
|
||||
void onDragEnd(double velocity) {
|
||||
if (_isSnapped) return;
|
||||
|
||||
final threshold = 0.45; // 45% 触发吸附
|
||||
final shouldSnap = _progress > threshold || velocity > 800;
|
||||
|
||||
if (shouldSnap) {
|
||||
snapOpen();
|
||||
} else {
|
||||
snapBack();
|
||||
}
|
||||
}
|
||||
|
||||
/// 吸附展开
|
||||
void snapOpen() {
|
||||
if (_isSnapped) return;
|
||||
_isSnapped = true;
|
||||
|
||||
_animationController?.reset();
|
||||
_animationController
|
||||
?.animateTo(
|
||||
1.0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeOutBack,
|
||||
)
|
||||
.then((_) {
|
||||
_progress = 1.0;
|
||||
notifyListeners();
|
||||
});
|
||||
|
||||
// 实时更新进度
|
||||
_animationController?.addListener(() {
|
||||
_progress = _animationController!.value;
|
||||
notifyListeners();
|
||||
});
|
||||
}
|
||||
|
||||
/// 回弹
|
||||
void snapBack() {
|
||||
if (_isSnapped) return;
|
||||
|
||||
_animationController?.reset();
|
||||
_animationController
|
||||
?.animateTo(
|
||||
0.0,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeOut,
|
||||
)
|
||||
.then((_) {
|
||||
_progress = 0.0;
|
||||
notifyListeners();
|
||||
});
|
||||
|
||||
_animationController?.addListener(() {
|
||||
_progress = _animationController!.value;
|
||||
notifyListeners();
|
||||
});
|
||||
}
|
||||
|
||||
/// 重置状态(退出页面时)
|
||||
void reset() {
|
||||
_isSnapped = false;
|
||||
_progress = 0.0;
|
||||
_animationController?.reset();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user