Flutter滑动顶部面板插件sliding_top_panel的使用
Flutter滑动顶部面板插件sliding_top_panel的使用
插件介绍
sliding_top_panel
是一个 Flutter 插件,允许你在应用中显示一个可滑动的顶部面板。这个插件在 Android 和 iOS 平台上都能正常工作。
安装
在你的 pubspec.yaml
文件中添加以下依赖:
dependencies:
sliding_top_panel: ^0.0.7
示例
以下是使用 sliding_top_panel
的一个完整示例。这个示例展示了如何创建一个包含可滑动顶部面板的页面,并且包含了一个浮动按钮来控制面板的打开和关闭。
完整示例代码
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:sliding_top_panel/sliding_top_panel.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: const MyHomePage(title: 'Example Sliding Panel'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ValueNotifier<bool> _isPanelVisible = ValueNotifier(false);
final SlidingPanelTopController _controller = SlidingPanelTopController();
@override
void initState() {
super.initState();
_controller.addListener(listenerController);
}
void listenerController() {
_isPanelVisible.value = _controller.isPanelOpen;
}
@override
void dispose() {
_controller.removeListener(listenerController);
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SlidingTopPanel(
// maxHeight: 100,
decorationPanel: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
),
controller: _controller,
header: Container(
color: Colors.white,
child: ListTile(
title: const Text("Header Panel"),
trailing: _buildArrowIconHeader(),
onTap: _controller.toggle,
),
),
panel: (_) => _buildListPanel(),
body: _buildGridList(),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: _controller.toggle,
tooltip: 'Toggle Panel',
icon: const Icon(Icons.toggle_off),
label: _buildTextFloatingButton(),
),
);
}
Widget _buildArrowIconHeader() {
return ValueListenableBuilder<bool>(
valueListenable: _isPanelVisible,
builder: (BuildContext _, bool isVisible, Widget? __) {
return Icon(
isVisible
? Icons.keyboard_arrow_up_rounded
: Icons.keyboard_arrow_down_rounded,
size: 20,
color: Colors.black45,
);
},
);
}
Widget _buildTextFloatingButton() {
return ValueListenableBuilder<bool>(
valueListenable: _isPanelVisible,
builder: (BuildContext _, bool isVisible, Widget? __) {
return Text(isVisible ? 'Close Panel' : 'Open Panel');
},
);
}
Widget _buildGridList() => GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemBuilder: (BuildContext _, int __) => Container(
color: _getColor(),
),
);
Widget _buildListPanel() => ListView.builder(
itemCount: 20,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext context, int index) => ListTile(
title: Text("Item $index"),
onTap: _controller.close,
),
);
Color _getColor() => Color.fromRGBO(
math.Random().nextInt(255),
math.Random().nextInt(255),
math.Random().nextInt(255),
1,
);
}
说明
-
导入依赖:
import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:sliding_top_panel/sliding_top_panel.dart';
-
创建
MyApp
类:class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), debugShowCheckedModeBanner: false, home: const MyHomePage(title: 'Example Sliding Panel'), ); } }
-
创建
MyHomePage
类:class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); }
-
创建
_MyHomePageState
类:class _MyHomePageState extends State<MyHomePage> { final ValueNotifier<bool> _isPanelVisible = ValueNotifier(false); final SlidingPanelTopController _controller = SlidingPanelTopController(); @override void initState() { super.initState(); _controller.addListener(listenerController); } void listenerController() { _isPanelVisible.value = _controller.isPanelOpen; } @override void dispose() { _controller.removeListener(listenerController); _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: SlidingTopPanel( decorationPanel: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( bottomLeft: Radius.circular(10), bottomRight: Radius.circular(10), ), ), controller: _controller, header: Container( color: Colors.white, child: ListTile( title: const Text("Header Panel"), trailing: _buildArrowIconHeader(), onTap: _controller.toggle, ), ), panel: (_) => _buildListPanel(), body: _buildGridList(), ), floatingActionButton: FloatingActionButton.extended( onPressed: _controller.toggle, tooltip: 'Toggle Panel', icon: const Icon(Icons.toggle_off), label: _buildTextFloatingButton(), ), ); } Widget _buildArrowIconHeader() { return ValueListenableBuilder<bool>( valueListenable: _isPanelVisible, builder: (BuildContext _, bool isVisible, Widget? __) { return Icon( isVisible ? Icons.keyboard_arrow_up_rounded : Icons.keyboard_arrow_down_rounded, size: 20, color: Colors.black45, ); }, ); } Widget _buildTextFloatingButton() { return ValueListenableBuilder<bool>( valueListenable: _isPanelVisible, builder: (BuildContext _, bool isVisible, Widget? __) { return Text(isVisible ? 'Close Panel' : 'Open Panel'); }, ); } Widget _buildGridList() => GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, ), itemBuilder: (BuildContext _, int __) => Container( color: _getColor(), ), ); Widget _buildListPanel() => ListView.builder( itemCount: 20, padding: EdgeInsets.zero, itemBuilder: (BuildContext context, int index) => ListTile( title: Text("Item $index"), onTap: _controller.close, ), ); Color _getColor() => Color.fromRGBO( math.Random().nextInt(255), math.Random().nextInt(255), math.Random().nextInt(255), 1, ); }
运行效果
运行上述代码后,你将看到一个包含可滑动顶部面板的页面。顶部面板可以通过点击列表项的头部或浮动按钮来打开和关闭。面板打开时,浮动按钮的文本会变为 “Close Panel”,图标也会相应变化。
希望这个示例对你有所帮助!如果你有任何问题,欢迎随时提问。
更多关于Flutter滑动顶部面板插件sliding_top_panel的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter滑动顶部面板插件sliding_top_panel的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter中使用sliding_top_panel
插件的一个基本示例。这个插件允许你实现一个可以滑动的顶部面板效果。首先,确保你已经在pubspec.yaml
文件中添加了sliding_top_panel
依赖:
dependencies:
flutter:
sdk: flutter
sliding_top_panel: ^x.y.z # 替换为最新版本号
然后,运行flutter pub get
来安装依赖。
接下来是一个完整的示例代码,展示了如何使用sliding_top_panel
插件:
import 'package:flutter/material.dart';
import 'package:sliding_top_panel/sliding_top_panel.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
)..addListener(() {
setState(() {});
});
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _togglePanel() {
setState(() {
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Sliding Top Panel Example'),
),
body: Stack(
children: [
// 主体内容
Container(
color: Colors.grey[200],
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Main Content',
style: TextStyle(fontSize: 24),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _togglePanel,
child: Text('Toggle Panel'),
),
],
),
),
),
// 滑动顶部面板
SlidingUpPanel(
panel: Center(
child: Container(
color: Colors.blue,
height: 200,
child: Center(
child: Text(
'This is the sliding panel!',
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
),
body: Container(), // 这里的body可以是空的,因为面板已经覆盖了它
collapsedHeight: 50,
borderRadius: BorderRadius.circular(16),
panelSnapSize: 200,
animationController: _controller,
animationCurve: Curves.easeInOut,
backdropEnabled: true,
parallaxOffset: _animation,
onDragEnd: (draggedHeight) {
if (draggedHeight > _controller.value * _controller.upperBound) {
_controller.forward();
} else {
_controller.reverse();
}
},
),
],
),
);
}
}
在这个示例中,我们创建了一个SlidingUpPanel
,它包含一个蓝色的顶部面板和主体内容。当用户点击按钮时,顶部面板会向上滑动(如果它当前是关闭的)或向下滑动(如果它当前是打开的)。
panel
参数定义了滑动面板的内容。collapsedHeight
定义了面板折叠时的高度。borderRadius
定义了面板的圆角。panelSnapSize
定义了面板完全展开时的高度。animationController
和animationCurve
用于控制动画效果。onDragEnd
回调用于处理拖动结束时的逻辑,确保面板根据拖动的高度正确展开或折叠。
请注意,SlidingUpPanel
组件的一些参数和用法可能会根据插件的更新而有所变化,因此请参考插件的官方文档以获取最新的信息和最佳实践。