1.生成页面 get create page content
商品详情页面布局监听滚动条事件改变导航动画
import 'package:flutter/material.dart';
import 'package:flutterdemo/app/services/screenAdapter.dart';
import 'package:get/get.dart';
import '../controllers/content_controller.dart';
class ContentView extends GetView<ContentController> {
const ContentView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true, // 实现透明导航
appBar: PreferredSize(
preferredSize: Size.fromHeight(ScreenAdapter.height(96)),
child: Obx(() =>
AppBar(
leading: Container(
alignment: Alignment.center,
child: SizedBox(
width: ScreenAdapter.width(88),
height: ScreenAdapter.width(88),
child: ElevatedButton(
onPressed: (){},
style: ButtonStyle(
// TODO ??
padding: MaterialStateProperty.all(
const EdgeInsets.all(0),
),
alignment: Alignment.center,
backgroundColor: MaterialStateProperty.all(Colors.black12),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(const CircleBorder()),
),
child: const Icon(Icons.arrow_back_ios_new_outlined)),
),
),
title: SizedBox(
width: ScreenAdapter.width(400),
height: ScreenAdapter.height(96),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(padding: EdgeInsets.all(0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"商品",
style: TextStyle(fontSize: ScreenAdapter.fontSize(36)),
),
Container(
margin: EdgeInsets.only(
top: ScreenAdapter.height(10),
),
width: ScreenAdapter.width(100),
height: ScreenAdapter.height(2),
color: Colors.red,
)
],
),
),
Padding(padding: EdgeInsets.all(0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"详情",
style: TextStyle(fontSize: ScreenAdapter.fontSize(36)),
),
Container(
margin: EdgeInsets.only(
top: ScreenAdapter.height(10),
),
width: ScreenAdapter.width(100),
height: ScreenAdapter.height(2),
color: Colors.red,
)
],
),
),
Padding(padding: EdgeInsets.all(0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"推荐",
style: TextStyle(fontSize: ScreenAdapter.fontSize(36)),
),
Container(
margin: EdgeInsets.only(
top: ScreenAdapter.height(10),
),
width: ScreenAdapter.width(100),
height: ScreenAdapter.height(2),
color: Colors.red,
)
],
),
),
],
),
),
centerTitle: true,
backgroundColor: Colors.white.withOpacity(controller.opacity.value), // 实现透明导航
elevation: 0,
actions: [
Container(
margin: EdgeInsets.only(right: ScreenAdapter.width(20)),
width: ScreenAdapter.width(88),
height: ScreenAdapter.width(88),
child: ElevatedButton(
onPressed: (){},
style: ButtonStyle(
padding: MaterialStateProperty.all(
const EdgeInsets.all(0),
),
alignment: Alignment.center,
backgroundColor: MaterialStateProperty.all(Colors.black12),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(const CircleBorder()),
),
child: const Icon(Icons.file_upload_outlined)
),
),
Container(
margin: EdgeInsets.only(right: ScreenAdapter.width(20)),
width: ScreenAdapter.width(88),
height: ScreenAdapter.width(88),
child: ElevatedButton(
onPressed: (){},
style: ButtonStyle(
padding: MaterialStateProperty.all(
const EdgeInsets.all(0),
),
alignment: Alignment.center,
backgroundColor: MaterialStateProperty.all(Colors.black12),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(const CircleBorder()),
),
child: const Icon(Icons.more_horiz_rounded)
),
)
],
)),
),
body: ListView(
controller: controller.scrollController,
children: [
Container(
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(300),
color: Colors.orange,
),
ListTile(
title: Text("我是一个内容列表"),
),
ListTile(
title: Text("我是一个内容列表"),
),
ListTile(
title: Text("我是一个内容列表"),
),
ListTile(
title: Text("我是一个内容列表"),
),
Container(
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(300),
color: Colors.orange,
),
ListTile(
title: Text("我是一个内容列表"),
),
ListTile(
title: Text("我是一个内容列表"),
),
ListTile(
title: Text("我是一个内容列表"),
),
ListTile(
title: Text("我是一个内容列表"),
),
Container(
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(300),
color: Colors.orange,
),
ListTile(
title: Text("我是一个内容列表"),
),
ListTile(
title: Text("我是一个内容列表"),
),
ListTile(
title: Text("我是一个内容列表"),
),
ListTile(
title: Text("我是一个内容列表"),
)
],
)
);
}
}
controller
RxDouble opacity = 0.0.obs;
final ScrollController scrollController = ScrollController();
@override
void onInit() {
super.onInit();
}
// 监听滚动条滚动事件
void scrollControllerListener(){
scrollController.addListener(() {
if(scrollController.position.pixels <=100){
opacity.value = scrollController.position.pixels/100;
print(opacity.value);
update();
}
});
}
二 顶部tab切换以及使用SingleChildScrollerView实现锚点效果
import 'package:flutter/material.dart';
import 'package:flutterdemo/app/services/screenAdapter.dart';
import 'package:get/get.dart';
import '../controllers/content_controller.dart';
class ContentView extends GetView<ContentController> {
const ContentView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true, // 实现透明导航
appBar: PreferredSize(
preferredSize: Size.fromHeight(ScreenAdapter.height(96)),
child: Obx(() =>
AppBar(
leading: Container(
alignment: Alignment.center,
child: SizedBox(
width: ScreenAdapter.width(88),
height: ScreenAdapter.width(88),
child: ElevatedButton(
onPressed: (){},
style: ButtonStyle(
// TODO ??
padding: MaterialStateProperty.all(
const EdgeInsets.all(0),
),
alignment: Alignment.center,
backgroundColor: MaterialStateProperty.all(Colors.black12),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(const CircleBorder()),
),
child: const Icon(Icons.arrow_back_ios_new_outlined)),
),
),
title: SizedBox(
width: ScreenAdapter.width(400),
height: ScreenAdapter.height(96),
child: controller.showTabs.value ? Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: controller.tabsList.map((v){
return InkWell(
onTap: (){
controller.changeSelectedTabsIndex(v["id"]);
// 跳转到指定的容器
if(v["id"] == 1){
Scrollable.ensureVisible(
controller.gk1.currentContext as BuildContext,
duration:const Duration(microseconds: 100)
);
}else if(v["id"] == 2){
Scrollable.ensureVisible(
controller.gk2.currentContext as BuildContext,
duration:const Duration(microseconds: 100)
);
}else if(v["id"] == 3){
Scrollable.ensureVisible(
controller.gk3.currentContext as BuildContext,
duration:const Duration(microseconds: 500)
);
}
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${v["title"]}",
style: TextStyle(fontSize: ScreenAdapter.fontSize(36)),
),
v["id"] == controller.selectedTabsIndex.value?
Container(
margin: EdgeInsets.only(
top: ScreenAdapter.height(10),
),
width: ScreenAdapter.width(100),
height: ScreenAdapter.height(2),
color: Colors.red,
)
: Container(
margin: EdgeInsets.only(
top: ScreenAdapter.height(10)
),
width: ScreenAdapter.width(100),
height: ScreenAdapter.height(2),
)
],
),
);
}).toList()
):const Text(""),
),
centerTitle: true,
backgroundColor: Colors.white.withOpacity(controller.opacity.value), // 实现透明导航
elevation: 0,
actions: [
Container(
margin: EdgeInsets.only(right: ScreenAdapter.width(20)),
width: ScreenAdapter.width(88),
height: ScreenAdapter.width(88),
child: ElevatedButton(
onPressed: (){},
style: ButtonStyle(
padding: MaterialStateProperty.all(
const EdgeInsets.all(0),
),
alignment: Alignment.center,
backgroundColor: MaterialStateProperty.all(Colors.black12),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(const CircleBorder()),
),
child: const Icon(Icons.file_upload_outlined)
),
),
Container(
margin: EdgeInsets.only(right: ScreenAdapter.width(20)),
width: ScreenAdapter.width(88),
height: ScreenAdapter.width(88),
child: ElevatedButton(
onPressed: (){},
style: ButtonStyle(
padding: MaterialStateProperty.all(
const EdgeInsets.all(0),
),
alignment: Alignment.center,
backgroundColor: MaterialStateProperty.all(Colors.black12),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(const CircleBorder()),
),
child: const Icon(Icons.more_horiz_rounded)
),
)
],
)),
),
body: SingleChildScrollView(
controller: controller.scrollController,
child: Column(
children: [
Container(
key: controller.gk1,
alignment: Alignment.center,
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(1800),
color: Colors.orange,
child: Text("商品",style: TextStyle(fontSize: 100)),
),
Container(
key: controller.gk2,
alignment: Alignment.center,
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(1800),
color: Colors.blue,
child: Text("详情",style: TextStyle(fontSize: 100)),
),
Container(
key: controller.gk3,
alignment: Alignment.center,
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(1800),
color: Colors.red,
child: Text("推荐",style: TextStyle(fontSize: 100)),
)
],
),
)
);
}
}
controller
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class ContentController extends GetxController {
//TODO: Implement ContentController
// 导航的透明度
RxDouble opacity = 0.0.obs;
final ScrollController scrollController = ScrollController();
GlobalKey gk1 = GlobalKey();
GlobalKey gk2 = GlobalKey();
GlobalKey gk3 = GlobalKey();
// 是否显示tabs
RxBool showTabs = false.obs;
List tabsList = [
{
"id":1,
"title":"商品"
},
{
"id":2,
"title":"详情"
},
{
"id":3,
"title":"推荐"
},
];
RxInt selectedTabsIndex = 1.obs;
@override
void onInit() {
super.onInit();
scrollControllerListener();
}
// 监听滚动条滚动事件
void scrollControllerListener(){
scrollController.addListener(() {
print("劲来");
if(scrollController.position.pixels <=100){
opacity.value = scrollController.position.pixels/100;
if(showTabs.value == true){
showTabs.value = false;
}
print(opacity.value);
update();
}else{
if(showTabs.value == false){
showTabs.value = true;
update();
}
}
});
}
@override
void onReady() {
super.onReady();
}
@override
void onClose() {
super.onClose();
}
void changeSelectedTabsIndex(index){
selectedTabsIndex.value = index;
update();
}
}
第三 使用showMenu 弹出菜单,使用定位实现底部浮动导航布局
import 'package:flutter/material.dart';
import 'package:flutterdemo/app/services/screenAdapter.dart';
import 'package:get/get.dart';
import '../controllers/content_controller.dart';
class ContentView extends GetView<ContentController> {
const ContentView({Key? key}) : super(key: key);
Widget _appBar(BuildContext context) {
return Obx(
() => AppBar(
leading: Container(
alignment: Alignment.center,
child: SizedBox(
width: ScreenAdapter.width(88),
height: ScreenAdapter.width(88),
child: ElevatedButton(
onPressed: (){},
style: ButtonStyle(
// TODO ??
padding: MaterialStateProperty.all(
const EdgeInsets.all(0),
),
alignment: Alignment.center,
backgroundColor: MaterialStateProperty.all(Colors.black12),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(const CircleBorder()),
),
child: const Icon(Icons.arrow_back_ios_new_outlined)),
),
),
title: SizedBox(
width: ScreenAdapter.width(400),
height: ScreenAdapter.height(96),
child: controller.showTabs.value ? Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: controller.tabsList.map((v){
return InkWell(
onTap: (){
controller.changeSelectedTabsIndex(v["id"]);
// 跳转到指定的容器
if(v["id"] == 1){
Scrollable.ensureVisible(
controller.gk1.currentContext as BuildContext,
duration:const Duration(microseconds: 100)
);
}else if(v["id"] == 2){
Scrollable.ensureVisible(
controller.gk2.currentContext as BuildContext,
duration:const Duration(microseconds: 100)
);
}else if(v["id"] == 3){
Scrollable.ensureVisible(
controller.gk3.currentContext as BuildContext,
duration:const Duration(microseconds: 500)
);
}
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${v["title"]}",
style: TextStyle(fontSize: ScreenAdapter.fontSize(36)),
),
v["id"] == controller.selectedTabsIndex.value?
Container(
margin: EdgeInsets.only(
top: ScreenAdapter.height(10),
),
width: ScreenAdapter.width(100),
height: ScreenAdapter.height(2),
color: Colors.red,
)
: Container(
margin: EdgeInsets.only(
top: ScreenAdapter.height(10)
),
width: ScreenAdapter.width(100),
height: ScreenAdapter.height(2),
)
],
),
);
}).toList()
):const Text(""),
),
centerTitle: true,
backgroundColor: Colors.white.withOpacity(controller.opacity.value), // 实现透明导航
elevation: 0,
actions: [
Container(
margin: EdgeInsets.only(right: ScreenAdapter.width(20)),
width: ScreenAdapter.width(88),
height: ScreenAdapter.width(88),
child: ElevatedButton(
onPressed: (){},
style: ButtonStyle(
padding: MaterialStateProperty.all(
const EdgeInsets.all(0),
),
alignment: Alignment.center,
backgroundColor: MaterialStateProperty.all(Colors.black12),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(const CircleBorder()),
),
child: const Icon(Icons.file_upload_outlined)
),
),
Container(
margin: EdgeInsets.only(right: ScreenAdapter.width(20)),
width: ScreenAdapter.width(88),
height: ScreenAdapter.width(88),
child: ElevatedButton(
onPressed: (){
showMenu(
color: Colors.black87.withOpacity(0.7),
context: context,
position: RelativeRect.fromLTRB( // todo
ScreenAdapter.width(800),
ScreenAdapter.height(220),
ScreenAdapter.width(20),
0),
items: [
PopupMenuItem(child: Row(
children: [
Icon(Icons.home,color: Colors.white),
Text('首页',style: TextStyle(color: Colors.white),)
],
)
),
PopupMenuItem(child: Row(
children: [
Icon(Icons.message,color: Colors.white),
Text('消息',style: TextStyle(color: Colors.white),)
],
)
),
PopupMenuItem(child: Row(
children: [
Icon(Icons.star,color: Colors.white),
Text('收藏',style: TextStyle(color: Colors.white),)
],
)
),
]
);
},
style: ButtonStyle(
padding: MaterialStateProperty.all(
const EdgeInsets.all(0),
),
alignment: Alignment.center,
backgroundColor: MaterialStateProperty.all(Colors.black12),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(const CircleBorder()),
),
child: const Icon(Icons.more_horiz_rounded)
),
)
],
)
);
}
Widget _body(){
return SingleChildScrollView(
controller: controller.scrollController,
child: Column(
children: [
Container(
key: controller.gk1,
alignment: Alignment.center,
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(1800),
color: Colors.orange,
child: Text("商品",style: TextStyle(fontSize: 100)),
),
Container(
key: controller.gk2,
alignment: Alignment.center,
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(1800),
color: Colors.blue,
child: Text("详情",style: TextStyle(fontSize: 100)),
),
Container(
key: controller.gk3,
alignment: Alignment.center,
width: ScreenAdapter.width(1080),
height: ScreenAdapter.height(1800),
color: Colors.red,
child: Text("推荐",style: TextStyle(fontSize: 100)),
)
],
),
);
}
Widget _bottom(){
return Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
height: ScreenAdapter.height(160),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
width: ScreenAdapter.width(2),color: Colors.black12
)
)
),
child: Row(
children: [
SizedBox(
width: ScreenAdapter.width(200),
height: ScreenAdapter.height(160),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.shopping_cart),
Text("购物车",style: TextStyle(fontSize: ScreenAdapter.fontSize(32)))
],
),
),
Expanded(
flex: 1,
child: Container(
height: ScreenAdapter.height(120),
margin: EdgeInsets.only(right: ScreenAdapter.width(20)),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
const Color.fromRGBO(255, 165, 0, 0.9)
),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))
)
),
onPressed: (){},
child: Text("加入购物车")),
)
),
Expanded(
flex: 1,
child: Container(
height: ScreenAdapter.height(120),
margin: EdgeInsets.only(right: ScreenAdapter.width(20)),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
const Color.fromRGBO(255, 1, 0, 0.9)
),
foregroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))
)
),
onPressed: (){},
child: Text("立即购买")),
))
],
),
));
}
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true, // 实现透明导航
appBar: PreferredSize(
preferredSize: Size.fromHeight(ScreenAdapter.height(120)),
child: _appBar(context),
),
body: Stack(
children: [
_body(),
_bottom(),
],
)
);
}
}