Skip to content

Instantly share code, notes, and snippets.

@doyle-flutter
Created September 14, 2021 10:39
Show Gist options
  • Save doyle-flutter/6d9ebca8a974374bc1d82d26e792db5d to your computer and use it in GitHub Desktop.
Save doyle-flutter/6d9ebca8a974374bc1d82d26e792db5d to your computer and use it in GitHub Desktop.
good & bed
import 'package:flutter/material.dart';
void main() => runApp(Sys());
class Sys extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
onGenerateRoute: (RouteSettings route){
// if(route.name == Main.path) return MaterialPageRoute(
// settings: RouteSettings(name: '/'),
// builder: (context) => Main(controller: MainController(),)
// );
return MaterialPageRoute(
settings: RouteSettings(name: '/'),
builder: (context) => Main(controller: MainController(),)
);
},
);
}
class MainController{}
class Main extends StatelessWidget {
final MainController controller;
const Main({Key? key, required this.controller}) : super(key: key);
static const String path = "/";
@override
Widget build(BuildContext context) => MainPage(controller: this.controller,);
}
class MainPage extends StatelessWidget {
final MainController controller;
const MainPage({Key? key, required this.controller}) : super(key: key);
@override
Widget build(BuildContext context) => this._wrapper(
context: context,
children: [
ProfileComponent(
imgSrc: "https://cdn.pixabay.com/photo/2016/03/31/19/58/avatar-1295429__480.png",
clientName: "홍길동",
),
ItemsViewComponent(
itemMenus: <String>["menu1","menu2","menu3"].map<TextButton>(
(String s) => TextButton(
child: Text(
s,
style:TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold
)
),
onPressed: (){},
)
).toList(),
itemOnPressed: (int itemIndex) => print("itemIndex : $itemIndex"),
itemIconOnPressed: (int itemIconIndex) => print("Icon : $itemIconIndex"),
items: <String>[
"https://cdn.pixabay.com/photo/2020/07/21/16/24/landscape-5426755__480.jpg",
"https://cdn.pixabay.com/photo/2021/09/10/22/28/smart-working-6614315__340.png",
"https://cdn.pixabay.com/photo/2021/09/09/07/54/woman-6609797__480.png",
"https://cdn.pixabay.com/photo/2021/08/23/17/53/cat-6568422__480.jpg",
].map<ItemsViewModel>((String img) => ItemsViewModel(imgSrc: img)).toList(),
height: MediaQuery.of(context).size.height*0.50,
),
ListItemComponent(
items: [
SalesModel(
imgSrc: "https://cdn.pixabay.com/photo/2021/09/06/00/19/eggs-6600556__480.png",
title: "Product1",
shopName: "shop111"
),
SalesModel(
imgSrc: "https://cdn.pixabay.com/photo/2021/09/06/00/22/wheat-flour-6600578__480.png",
title: "Product2",
shopName: "shop22222"
),
SalesModel(
imgSrc: "https://cdn.pixabay.com/photo/2021/08/28/19/49/donut-6581822__480.png",
title: "Product3",
shopName: "shop3333"
),
SalesModel(
imgSrc: "https://cdn.pixabay.com/photo/2021/01/15/17/01/green-5919790__480.jpg",
title: "Product4",
shopName: "shop4"
)
],
)
]
);
Widget _wrapper({required BuildContext context, required List<Widget> children}) => Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
title: Text("🧑‍💻 JamesDev", style: TextStyle(color: Colors.black)),
centerTitle: true
),
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.only(bottom: 40.0),
color: Colors.grey[200],
child: Column(
children: children,
),
),
),
bottomNavigationBar: BottomNavigationBar(
showSelectedLabels: false,
showUnselectedLabels: false,
selectedItemColor: Colors.deepOrangeAccent,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.note_sharp), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.music_note), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.shopping_cart), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.person), label: "")
],
),
);
}
class ProfileComponent extends StatelessWidget {
final double? width;
final double? height;
final String imgSrc;
final String clientName;
final EdgeInsets? margin;
final EdgeInsets? padding;
TextStyle? titleTextStyle;
ProfileComponent({
Key? key,
this.width,
this.height,
required this.imgSrc,
required this.clientName,
this.margin,
this.padding,
this.titleTextStyle,
}) : super(key: key);
final TextStyle _defaultTitleTextStyle = TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
);
@override
Widget build(BuildContext context) => Card(
margin: this.margin ?? EdgeInsets.only(bottom: 30.0, left: 5.0, right: 5.0),
child: Container(
width: this.width,
height: this.height,
padding: this.padding ?? EdgeInsets.all(20.0),
child: Column(
children: [
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Text(
"안녕하세요, ${this.clientName}님?!",
style: this.titleTextStyle ?? this._defaultTitleTextStyle,
),
),
Container(
child: Text("오늘도 지구를 지켜츄세요 ❤️"),
)
],
)
),
Container(
child: CircleAvatar(
backgroundImage: NetworkImage(this.imgSrc),
minRadius: 40.0,
backgroundColor: Colors.white,
child: Container(
width: 80.0,
height: 80.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(80.0),
border: Border.all(color: Colors.grey)
)
),
)
)
],
),
),
Container(
margin: EdgeInsets.only(top:20.0),
child: TextField(
readOnly: true,
decoration: InputDecoration(
filled: true,
fillColor: Colors.amberAccent,
suffixIcon: Container(
padding: EdgeInsets.all(10.0),
child: Icon(
Icons.search,
color: Colors.white
)
),
contentPadding: EdgeInsets.all(10.0),
hintText: "Search...",
hintStyle: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20.0
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide.none
)
),
),
)
],
),
),
);
}
class ItemsViewModel{
final String imgSrc;
const ItemsViewModel({required this.imgSrc});
}
/// 좋은 예시
class ItemsViewComponent extends StatefulWidget {
late Axis scrollAxis;
final List<ItemsViewModel> items;
final EdgeInsets? margin;
final EdgeInsets? padding;
final double? width;
final double height;
final void Function(int) itemOnPressed;
final void Function(int) itemIconOnPressed;
final List<TextButton> itemMenus;
ItemsViewComponent({
Key? key,
this.width,
required this.height,
Axis scrollAxis = Axis.horizontal,
required this.items,
required this.itemOnPressed,
required this.itemIconOnPressed,
required this.itemMenus,
this.margin,
this.padding
}) : super(key: key){
this.scrollAxis = scrollAxis;
}
@override
State<ItemsViewComponent> createState() => _ItemsViewComponentState();
}
class _ItemsViewComponentState extends State<ItemsViewComponent> {
final PageController _controller = PageController(
viewportFraction: 0.8,
keepPage: false
);
int _pageIndex = 0;
@override
void initState() {
this._controller.addListener(() {
if(!this._controller.hasClients) return;
if(!this.mounted) return;
setState((){});
});
super.initState();
}
@override
void dispose() {
this._controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Card(
margin: this.widget.margin ?? EdgeInsets.only(bottom: 30.0, left: 5.0, right: 5.0),
child: Container(
color: Colors.white,
width: this.widget.width,
height: this.widget.height,
padding: this.widget.padding ?? EdgeInsets.symmetric(vertical: 14.0),
child: PageView.builder(
scrollDirection: this.widget.scrollAxis,
controller: this._controller,
padEnds: false,
itemCount: this.widget.items.length,
onPageChanged: (int currentPageIndex){
setState(() {
this._pageIndex = currentPageIndex;
});
},
itemBuilder: (BuildContext context, int index){
return AnimatedBuilder(
animation: this._controller,
builder: (BuildContext context, Widget? child) {
double value = 1.0;
if (_controller.position.haveDimensions) {
value = _controller.page! - index;
value = (1 - (value.abs() * .3)).clamp(0.0, 1.0);
}
return Container(
margin: EdgeInsets.symmetric(horizontal: 10.0),
child: Center(
child: SizedBox(
height: Curves.easeOut.transform(value) * widget.height,
width: Curves.easeOut.transform(value) * (MediaQuery.of(context).size.width),
child: child,
),
),
);
},
child: Opacity(
opacity: this._pageIndex == index ? 1.0 : 0.3,
child: index == 0 ? this._firstItemWrapper(this._item(widget.items[index], index)) : this._item(widget.items[index], index)
),
);
},
),
),
);
Widget _firstItemWrapper(Widget content) => Container(
child: Stack(
children: [
content,
Positioned(
left: 0,
top: 0,
bottom: 0,
child: Container(
padding: EdgeInsets.only(left: 20.0),
child: Column(
children: this.widget.itemMenus.map<Widget>(
(TextButton s) => Expanded(
child: Container(
alignment: Alignment.center,
child: RotatedBox(
quarterTurns: -1,
child: s,
),
)
)
).toList(),
)
),
)
],
)
);
Widget _item(ItemsViewModel model, int index) => Container(
width: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
model.imgSrc
),
),
borderRadius: BorderRadius.circular(10.0)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: EdgeInsets.all(10.0),
alignment: Alignment.centerRight,
child: IconButton(
icon: Icon(
Icons.more_horiz,
color: Colors.white
),
onPressed: () => this.widget.itemIconOnPressed(index),
)
),
Container(
padding: EdgeInsets.only(bottom: 10.0),
child: MaterialButton(
child: Text(
"Click",
style: TextStyle(
fontWeight: FontWeight.bold
),
),
onPressed: () => this.widget.itemOnPressed(index),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
minWidth: 200.0,
color: Colors.orangeAccent,
textColor: Colors.white
)
)
],
),
);
}
abstract class ItemModel{
final String imgSrc = "";
final String title = "";
}
class SalesModel implements ItemModel{
@override
final String imgSrc;
@override
final String title;
final String shopName;
const SalesModel({required this.imgSrc, required this.title, required this.shopName});
}
/// 나쁜 예시
class ListItemComponent extends StatelessWidget {
final EdgeInsets? margin;
final EdgeInsets? padding;
final List<ItemModel> items;
const ListItemComponent({
Key? key,
required this.items,
this.margin,
this.padding
}) : super(key: key);
@override
Widget build(BuildContext context) => Card(
margin: this.margin ?? EdgeInsets.only(bottom: 30.0, left: 5.0, right: 5.0),
child: Container(
padding: this.padding ?? EdgeInsets.only(bottom: 20.0),
color: Colors.white,
child: Column(
children: [
Container(
padding: EdgeInsets.only(
top: 30.0,
left: 20.0,
bottom: 10.0
),
alignment: Alignment.centerLeft,
child: Text(
'TITLE',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold
)
),
),
Container(
child: Row(
children: <String>["menu1", "menu2", "menu3"].map<Widget>(
(String m) => Expanded(
child: Container(
padding: EdgeInsets.symmetric(
vertical: 4.0,
horizontal: 10.0
),
child: MaterialButton(
color: m == "menu1" ? Colors.orange : Colors.grey,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
side: BorderSide(color: m == "menu1" ? Colors.transparent : Colors.grey)
),
child: Text(m),
onPressed: (){}
),
),
)
).toList(),
),
),
Container(
child: Column(
children: this.items.map<Widget>(
(ItemModel model) => Material(
color: Colors.white,
child: InkWell(
onTap: (){},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 20.0),
child: Row(
children: [
Container(
width: 60.0,
height: 60.0,
padding: EdgeInsets.all(10.0),
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(model.imgSrc)
),
borderRadius: BorderRadius.circular(20.0),
border: Border.all(color: Colors.grey)
),
),
SizedBox(width: 30.0),
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
model.title,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
Text(
(model as SalesModel).shopName,
style: TextStyle(
color: Colors.deepOrangeAccent
),
),
],
)
),
],
),
),
),
)
).toList(),
),
),
],
)
),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment