Related
I'm trying to make a music app and I'm in trouble with modifying positions of 'Playlist of the week' text and the Listview of the images right now. I want to make those two properties more upwards but I have no idea what to do.
This is my home.dart file
import 'package:flutter/material.dart';
import 'package:secondlife_mobile/PageViewHolder.dart';
import 'package:provider/provider.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final PageStorageBucket bucket = PageStorageBucket();
late PageViewHolder holder;
late PageController _controller;
double fraction =
0.57; // By using this fraction, we're telling the PageView to show the 50% of the previous and the next page area along with the main page
#override
void initState() {
super.initState();
holder = PageViewHolder(value: 2.0);
_controller = PageController(initialPage: 2, viewportFraction: fraction);
_controller.addListener(() {
holder.setValue(_controller.page);
});
}
int index = 1;
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: const Color.fromARGB(255, 223, 234, 244),
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const Text('AppBar'),
),
body: SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 30,
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 35),
child: Text(
'Playlist for you',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w400,
),
),
),
const SizedBox(height: 35),
Container(
child: Center(
child: AspectRatio(
aspectRatio: 1,
child: ChangeNotifierProvider<PageViewHolder>.value(
value: holder,
child: PageView.builder(
controller: _controller,
itemCount: 4,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
return MyPage(
number: index.toDouble(),
fraction: fraction,
);
}),
),
),
),
),
////Your Playlist of the week text
const Padding(
padding: EdgeInsets.symmetric(horizontal: 35),
child: Text(
'Playlist of the week',
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w600,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 35),
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 150,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
InkWell(
onTap: () {},
child: Ink(
child: SizedBox(
height: 160.0,
width: 200.0,
child: Image.asset(
'assets/images/album1.jpg',
height: 160.0,
width: 200.0,
),
),
),
),
const SizedBox(
width: 30,
),
InkWell(
onTap: () {},
child: Ink(
child: SizedBox(
height: 160.0,
width: 200.0,
child: Image.asset(
'assets/images/album2.jpg',
height: 160.0,
width: 200.0,
),
),
),
),
const SizedBox(
width: 30,
),
InkWell(
onTap: () {},
child: Ink(
child: SizedBox(
height: 160.0,
width: 200.0,
child: Image.asset(
'assets/images/album3.jpg',
height: 160.0,
width: 200.0,
),
),
),
),
const SizedBox(
width: 30,
),
InkWell(
onTap: () {},
child: Ink(
child: SizedBox(
height: 160.0,
width: 200.0,
child: Image.asset(
'assets/images/album4.jpg',
height: 160.0,
width: 200.0,
),
),
),
),
const SizedBox(
width: 30,
),
InkWell(
onTap: () {},
child: Ink(
child: SizedBox(
height: 160.0,
width: 200.0,
child: Image.asset(
'assets/images/album5.jpg',
height: 160.0,
width: 200.0,
),
),
),
),
],
),
),
],
),
),
),
],
),
),
),
),
);
}
}
class MyPage extends StatelessWidget {
final number;
final double? fraction;
const MyPage({super.key, this.number, this.fraction});
#override
Widget build(BuildContext context) {
double? value = Provider.of<PageViewHolder>(context).value;
double diff = (number - value);
// diff is negative = left page
// diff is 0 = current page
// diff is positive = next page
//Matrix for Elements
final Matrix4 pvMatrix = Matrix4.identity()
..setEntry(3, 2, 1 / 0.9) //Increasing Scale by 90%
..setEntry(1, 1, fraction!) //Changing Scale Along Y Axis
..setEntry(3, 0, 0.004 * -diff); //Changing Perspective Along X Axis
final Matrix4 shadowMatrix = Matrix4.identity()
..setEntry(3, 3, 1 / 1.6) //Increasing Scale by 60%
..setEntry(3, 1, -0.004) //Changing Scale Along Y Axis
..setEntry(3, 0, 0.002 * diff) //Changing Perspective along X Axis
..rotateX(1.309); //Rotating Shadow along X Axis
return Stack(
fit: StackFit.expand,
alignment: FractionalOffset.center,
children: [
Transform.translate(
offset: const Offset(0.0, -47.5),
child: Transform(
transform: pvMatrix,
alignment: FractionalOffset.center,
child: Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
blurRadius: 11.0,
spreadRadius: 4.0,
offset: const Offset(
13.0, 35.0), // shadow direction: bottom right
)
]),
child: Image.asset(
"assets/images/image_${number.toInt() + 1}.jpg",
fit: BoxFit.fill),
),
),
),
],
);
}
}
And this is the image that I'm expecting right now.
Yeah, I solved it with wrapping the Padding of both text and the ListView with Transform.translate and did some tinkering with the offset.
Thank God I solved this! :)
Try to place a column inside the singlechildscrollview and define mainaxisalignment as min
Set height property of Container widget wrapping PageView.
I'm using SizeTransition to animate the width of a container.
This container is supposed to have rounded corners.
The problem is that the rounded corners only work when the sizeTransition is completed. If it is not completed, they remain square (as is shown in the gif below).
My code:
class DemoPage extends StatefulWidget {
const DemoPage({Key? key}) : super(key: key);
#override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
#override
void initState() {
super.initState();
_controller =
AnimationController(duration: const Duration(seconds: 5), vsync: this);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
constraints: const BoxConstraints.expand(),
color: Colors.black,
child: Center(
child: Column(
children: [
const SizedBox(height: 100),
Stack(
alignment: Alignment.centerLeft,
children: [
Container(
width: 300,
height: 20,
decoration: BoxDecoration(
color: const Color(0XFFC41D3D).withOpacity(0.5),
borderRadius:
const BorderRadius.all(Radius.circular(15))),
),
SizeTransition(
axis: Axis.horizontal,
sizeFactor: Tween(begin: 0.0, end: 1.0)
.chain(CurveTween(curve: const Interval(0.0, 0.4)))
.animate(_controller),
/// the container whose border radius is not working as expected
child: Container(
width: 300,
height: 20,
decoration: BoxDecoration(
color: const Color(0XFFC41D3D),
borderRadius: BorderRadius.circular(15.0)),
),
),
],
),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_controller.repeat();
},
child: const Icon(Icons.play_arrow),
),
);
}
}
What should I do to solve the problem?
You can Wrap your stack widget and change its clipBehavior,Try this:
Container(
color: Colors.black,
constraints: const BoxConstraints.expand(),
child: Center(
child: Column(
children: [
const SizedBox(height: 100),
Container( // add this.
clipBehavior: Clip.antiAlias,
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(15.0)),
child: Stack(
alignment: Alignment.centerLeft,
children: [
Container(
width: 300,
height: 20,
decoration: BoxDecoration(
color: const Color(0XFFC41D3D).withOpacity(0.5),
borderRadius:
const BorderRadius.all(Radius.circular(15))),
),
SizeTransition(
axis: Axis.horizontal,
sizeFactor: Tween(begin: 0.0, end: 1.0)
.chain(CurveTween(curve: const Interval(0.0, 0.4)))
.animate(_controller),
/// the container whose border radius is not working as expected
child: Container(
width: 300,
height: 20,
decoration: BoxDecoration(
color: const Color(0XFFC41D3D),
borderRadius: BorderRadius.circular(15.0)),
),
),
],
),
),
],
),
),
)
You can just wrap SizeTransition with ClipRRect which provide more realistic shape.
ClipRRect(
borderRadius: BorderRadius.circular(15.0),
child: SizeTransition(
I'm trying to achieve the skeleton view as shown in the attachment but couldn't get it exactly like shown, i have tried Shimmer package, the problem is gradient or mask width is more. Kindly help with sample for to achieve the same.
Used the shimmer: ^2.0.0
My ListView
return Padding(
padding: const EdgeInsets.only(top: 16),
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return ShimmerItem();
},
itemCount: 10,
),
);
ShimmerItem Widget:
class ShimmerItem extends StatelessWidget {
const ShimmerItem({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.only(left: 16, right: 16, bottom: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
color: Theme.of(context).cardTheme.color,
child: Container(
margin: EdgeInsets.only(left: 16, bottom: 8, top: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(right: 32.0),
child: ShimmerWidget.rectangular(
height: 16,
width: MediaQuery.of(context).size.width * 0.9,
)),
Padding(
padding: const EdgeInsets.only(right: 32.0, top: 8),
child: ShimmerWidget.rectangular(
height: 16,
width: MediaQuery.of(context).size.width * 0.6,
),
),
Padding(
padding: const EdgeInsets.only(top: 16, bottom: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
ShimmerWidget.rectangular(
height: 16,
width: MediaQuery.of(context).size.width * 0.4,
),
SizedBox(
width: 10,
),
ShimmerWidget.rectangular(
height: 16,
width: MediaQuery.of(context).size.width * 0.4,
),
],
),
),
],
),
),
);
}
}
ShimmerWidget Class:
class ShimmerWidget extends StatelessWidget {
final double width;
final double height;
final ShapeBorder shapeBorder;
const ShimmerWidget.rectangular(
{this.width = double.infinity, required this.height})
: this.shapeBorder = const RoundedRectangleBorder();
const ShimmerWidget.circular(
{this.width = double.infinity,
required this.height,
this.shapeBorder = const CircleBorder()});
#override
Widget build(BuildContext context) => Shimmer.fromColors(
baseColor:
ColorHelper.colorWithTransparency(AppColors.shimmer_bg_color,
100),
highlightColor:
ColorHelper.colorWithTransparency(AppColors.shimmer_color_dark,
20),
period: Duration(milliseconds: 1500),
child: Container(
width: width,
height: height,
decoration: ShapeDecoration(
color: AppColors.shimmer_bg_color,
shape: shapeBorder,
),
),
);
}
We can use LayoutBuilder for measurement, which is depending on parent size and perfect for this case.
To struct the same UI, I am just constructing the ShimmerItem widget, rest of widget will be same.
To get rounded border I am using ClipRRect with providing borderRadius.
Padding to control the sounded spacing and SizedBox to provide space on Column's children.
Used Row's mainAxisAlignment: MainAxisAlignment.spaceBetween,to separate last two shimmer widgets.
Resource about layout-basics.
class ShimmerItem extends StatelessWidget {
const ShimmerItem({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final _border = BorderRadius.circular(12);
final double _bHeight = 24;
return LayoutBuilder(
builder: (context, constraints) => Padding(
padding: const EdgeInsets.all(12.0), //outside the card
child: Container(
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
color: Colors.grey,
),
padding: const EdgeInsets.all(8), // inner padding
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//* top large two
ClipRRect(
borderRadius: _border,
child: ShimmerWidget.rectangular(
height: _bHeight,
width: constraints.maxWidth,
),
),
const SizedBox(height: 8),
ClipRRect(
borderRadius: _border,
child: ShimmerWidget.rectangular(
height: _bHeight * .75,
width: constraints.maxWidth,
),
),
const SizedBox(height: 8),
//3rd row
ClipRRect(
borderRadius: _border,
child: ShimmerWidget.rectangular(
height: _bHeight * .75,
width: constraints.maxWidth * 0.6,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClipRRect(
borderRadius: _border,
child: ShimmerWidget.rectangular(
height: _bHeight,
width: constraints.maxWidth * 0.4,
),
),
ClipRRect(
borderRadius: _border,
child: ShimmerWidget.rectangular(
height: _bHeight,
width: constraints.maxWidth * 0.4,
),
),
],
),
],
),
),
),
);
}
}
I am using demo color.
You need wrap all your child inside 1 bigger Shimmer wrapper to do that, not Shimmer on every small retangle.
I have project code for this in my laptop but im working afar, sorry.
Hello Guys I would like to ask is it possible to achieve this kind of design using code? I really got stuck, here is design I would like to achieve
but the real problem is I only achieve this
this is my sample code:
in my main:
return Scaffold(
backgroundColor: Color(0xff012a60),
body: Stack(children: <Widget>[
/*_AnimatedCircle(
outerController: outerController,
innerController: innerController,
),*/
_OuterCircle(circleColor: Colors.blueGrey[900].withOpacity(.8)),
Column(children: <Widget>[
const Spacer(flex: 50),
Expanded(flex: 30, child: Container(color: Colors.white)),
const Spacer(flex: 20),
]),
Row(children: <Widget>[
const Spacer(flex: 80),
Transform.scale(
scale: 2.5,
child: Container(
width: MediaQuery.of(context).size.width * 0.2,
decoration: const BoxDecoration(
color: Colors.red, shape: BoxShape.circle)),
),
]),
// _OuterCircle(circleColor: Colors.blueAccent.withOpacity(.25)),
Row(children: <Widget>[
const Spacer(flex: 80),
Column(children: [
Spacer(flex: 60),
Transform.scale(
scale: 2.5,
child: Container(
width: MediaQuery.of(context).size.width * 0.2,
height: MediaQuery.of(context).size.width * 0.05,
decoration: const BoxDecoration(color: Colors.green)),
),
Spacer(flex: 24),
]),
]),
]),
);
and this is my other class
class _OuterCircle extends StatelessWidget {
const _OuterCircle({Key key, this.circleColor}) : super(key: key);
final Color circleColor;
#override
Widget build(BuildContext context) {
return Transform.scale(
scale: 2,
child: Container(
width: MediaQuery.of(context).size.width * 0.47,
decoration: BoxDecoration(shape: BoxShape.circle, color: circleColor),
));
}
}
Please help I really stuck how to achieve this kind of design in dart code
I think it is easier to break down the geometry problem from the largest area to small area.
The key point of achieve this is using Clip (ClipOval, ClipRect...)
The upper part can be draw by using right circle to clip left circle
The lower part can be draw by using right circle to clip inner rectangle
Scale the stack area
Draw large left circle (area 1)
Draw middle white rectangle (area 2)
Draw right circle with rectangle inside (area 3)
Draw the middle intersection part (area 4)
Widgets in used: ClipOval, FractionallySizedBox, AspectRatio,
The left Big Circle
class BigCircle extends StatelessWidget {
const BigCircle({this.color,Key key}):super(key: key);
final Color color;
#override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
),
),
);
}
}
The custom oval clipper (clip right white circle area)
class CustomClipOval extends CustomClipper<Rect> {
#override
Rect getClip(Size size) {
final width = size.width * 0.42;
return Rect.fromLTRB(
size.width - width,
(size.height - width) * 0.5,
size.width,
(size.height + width) * 0.5,
);
}
#override
bool shouldReclip(covariant CustomClipper<Rect> oldClipper) {
return false;
}
}
Finally the stack
return Scaffold(
backgroundColor: const Color(0xff004471),
body: Transform.scale(
scale: 1.19,
child: Stack(children: <Widget>[
// Area 1
const Align(
alignment: Alignment.centerLeft,
child: BigCircle(
color: Color(0xff022c66),
),
),
// Area 2
Align(
alignment: const Alignment(0, 0.4),
child: FractionallySizedBox(
heightFactor: 0.23,
child: Container(
color: Colors.white,
),
),
),
// Area 3
ClipOval(
clipper: CustomClipOval(),
child: Container(
alignment: const Alignment(0, 0.46),
color: Colors.white,
child: FractionallySizedBox(
heightFactor: 0.14,
child: Container(
color: const Color(0xff335f86),
),
),
),
),
// Area 4
ClipOval(
clipper: CustomClipOval(),
child: const Align(
alignment: Alignment.centerLeft,
child: BigCircle(color: Color(0xff647294),),
),
),
]),
),
);
title basically explains the error method i'm recieving. sorry for the huge code, but i'm basically just trying to make a call to onboarding to flip the page when a user touches the "next" text. (onTap:() => _OnboardingState.jumpForward())"
how can i do this?
i've tried using streams (i'm pretty bad with it) and maybe a solution would be bloc related. idk. i'm sure it's a pretty easy fix
import 'package:flutter/material.dart';
import '../../styling/canvas.dart';
import '../../styling/theme.dart';
import 'dart:async';
class Onboarding extends StatefulWidget {
#override
_OnboardingState createState() => _OnboardingState();
}
class _OnboardingState extends State<Onboarding> {
PageController onboardingController;
void jumpForward() async {
onboardingController.nextPage(
curve: Curves.easeIn,
duration: Duration(milliseconds: 200)
);
}
#override
Widget build(BuildContext context) {
return PageView(
controller: onboardingController,
pageSnapping: true,
children: <Widget>[
OnboardingPage(viewModel:pages[0]),
OnboardingPage(viewModel:pages[1]),
OnboardingPage(viewModel:pages[2]),
]
);
}
// jumpTo() {
// hello.jump
// }
}
class PageViewModel{
PageViewModel({
this.title,
this.description,
this.id,
});
final String title;
final String description;
final int id;
}
final pages = [
PageViewModel(
title: "Trade smart",
description:
"Filter stocks by metrics like short interest and short interest change.",
id: 1,
),
PageViewModel(
title: "Connect",
description:
"Filter stocks by metrics like short interest and short interest change.",
id: 2,
),
PageViewModel(
title: "Get an edge",
description:
"View legal insider trades filed with the SEC, made by top executives.",
id: 3,
),
];
class OnboardingPage extends StatelessWidget {
OnboardingPage({this.viewModel});
final PageViewModel viewModel;
#override
Widget build(BuildContext context) {
double _height = MediaQuery.of(context).size.height;
double _width = MediaQuery.of(context).size.width;
final double _circleHeight = .022 * _height;
return Scaffold(
body: Container(
color: lightTheme.backgroundColor,
height: _height,
width: _width,
child: Padding(
padding: EdgeInsets.fromLTRB(0.0, .1 * _height, 0.0, .1 * _height),
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(
.044 * _width, 0.0, .044 * _width, .022 * _height),
child: Container(
//illustration
decoration:
returnCanvasStyle(), //todo: change color to theme bloc
width: _width,
height: .433 * _height,
),
),
Padding(
padding:
EdgeInsets.fromLTRB(.044 * _width, 0.0, .044 * _width, 0.0),
child: Container(
decoration: returnCanvasStyle(),
width: _width,
height: .344 * _height, //todo: change height
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(0.022 * _width,
0.022 * _height, 0.022 * _width, 0.0),
child: Text(
viewModel.title,
style: lightTheme.primaryTextTheme.display1,
textAlign: TextAlign.center,
),
),
Padding(
padding: EdgeInsets.fromLTRB(0.044 * _width,
0.022 * _height, 0.044 * _width, 0.033 * _height),
child: Text(
viewModel.description,
style: lightTheme.primaryTextTheme.body1,
softWrap: true,
textAlign: TextAlign.center,
),
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(
0.0, 0.0, .066 * _width, 0.0),
child: Container(
width: _circleHeight,
height: _circleHeight,
//color: Colors.red,
decoration: BoxDecoration(
border: Border.all(
color: lightTheme.primaryColor,
width: .0055 * _height,
),
borderRadius: BorderRadius.all(
Radius.circular(_circleHeight)),
color: lightTheme.primaryColor),
),
),
Padding(
padding: EdgeInsets.fromLTRB(
0.0, 0.0, .066 * _width, 0.0),
child: Container(
width: _circleHeight,
height: _circleHeight,
//color: Colors.red,
decoration: BoxDecoration(
border: Border.all(
color: lightTheme.primaryColor,
width: .0055 * _height,
),
borderRadius: BorderRadius.all(
Radius.circular(_circleHeight)),
color: Colors.transparent),
),
),
Padding(
padding: EdgeInsets.fromLTRB(
0.0, 0.0, .0944 * _width, 0.0),
child: Container(
width: _circleHeight,
height: _circleHeight,
//color: Colors.red,
decoration: BoxDecoration(
border: Border.all(
color: lightTheme.primaryColor,
width: .0055 * _height,
),
borderRadius: BorderRadius.all(
Radius.circular(_circleHeight)),
color: Colors.transparent),
),
),
Padding(
padding: EdgeInsets.fromLTRB(
0.0, 0.0, .119 * _width, 0.0),
child: GestureDetector(
onTap:() => _OnboardingState.jumpForward(),
child: Text(
"NEXT",
style: lightTheme.primaryTextTheme.button,
)),)
],
)
],
),
),
)
],
),
),
),
);
}
}
If you want to do it that way just use a callback for your State method. You are trying to access a non-static method in a static way, plus, you're doing it wrong because even if the method was static, you wouldn't be accessing the active State and controller.
So, by using a callback, you want to pass it on the constructor of your class
class OnboardingPage extends StatelessWidget {
OnboardingPage({this.viewModel, this.onNextPressed});
final PageViewModel viewModel;
final VoidCallback onNextPressed;
(...)
Call it on your NEXT tap
GestureDetector(
onTap:() => onNextPressed(),
child: Text(
"NEXT",
style: lightTheme.primaryTextTheme.button,
)
)
And then passing the reference when adding the OnboardingPage to your widget tree in your build method
OnboardingPage(viewModel:pages[0],onNextPressed: jumpForward)