Flutter skeleton view shimmer view - flutter

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.

Related

remove excess space at the bottom of my pageview.builder widget

I am trying to remove the excess space at the bottom of my widget but have not been able to do so. since I am using a page builder with a lot of text. I have tried adding the height manually but its not enough since i cant predict the size of the text.
import 'package:flutter/material.dart';
import 'package:flutter_lorem/flutter_lorem.dart';
import 'package:blink/core/widgets/widgets.dart';
import 'package:blink/feeds/feeds_details/widgets/widgets.dart';
import 'package:blink/gen/assets.gen.dart';
class FeedsDetailPage extends StatelessWidget {
const FeedsDetailPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const FeedsDetailView();
}
}
class FeedsDetailView extends StatelessWidget {
const FeedsDetailView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final String text1 = lorem(paragraphs: 2, words: 55);
final String text2 = lorem(paragraphs: 9, words: 500);
final String text3 = lorem(paragraphs: 10, words: 400);
final String text4 = lorem(paragraphs: 8, words: 2000);
final String text5 = lorem(paragraphs: 12, words: 500);
final textList = [
text3,
text4,
text5,
];
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Container(
child: Stack(
children: [
Positioned(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 368,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
//color: Colors.blue,
),
child: Assets.images.nightBuilding.image(
fit: BoxFit.cover,
),
),
),
),
Positioned(
top: 250,
left: 20,
child: Container(
height: 60,
width: 350,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Theme.of(context)
.backgroundColor
.computeLuminance() >
0.5
? Colors.black
: Colors.white,
),
child: AppMediumText(text: text1),
),
),
Positioned(
top: 334,
right: 33,
child: ElevatedButtonSmall(
onpressed: () {},
text: '',
useIcon: true,
icon: Icons.account_balance,
fizedSize: const Size(50, 50),
radius: 35,
),
),
Positioned(
top: 334,
right: 105,
child: ElevatedButtonSmall(
onpressed: () {},
text: '',
useIcon: true,
icon: Icons.text_fields,
fizedSize: const Size(50, 50),
radius: 35,
),
),
],
),
),
const SizedBox(height: 8),
Divider(
color: Theme.of(context).colorScheme.secondary,
indent: 50,
endIndent: 50,
),
Container(
width: 380,
height: double.maxFinite,
child: PageView.builder(
itemCount: textList.length + 1,
itemBuilder: (context, index) {
if (index == 0) {
return Column(
children: [
const SizedBox(height: 14),
Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: SizedBox(
width: 350,
height: double.maxFinite,
child: AppSmallText(
text: text2.replaceFirst(
text2[0],
text2[0].toUpperCase(),
),
),
),
),
],
);
} else {
return Column(
children: [
const SizedBox(height: 14),
Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: SizedBox(
width: 350,
height: double.maxFinite,
child: AppSmallText(
text: textList[index - 1].replaceFirst(
textList[0],
textList[0].toUpperCase(),
),
),
),
),
],
);
}
},
),
)
],
),
),
);
}
}
Ignore this line it is just an excess line. I am trying to remove the excess space at the bottom of my widget but have not been able to do so. since I am using a page builder with a lot of text. I have tried adding the height manually but its not enough since i cant predict the size of the text.
You can try mainAxisSize: MainAxisSize.min in your columns and remove height: double.maxFinite:
class FeedsDetailPage extends StatelessWidget {
const FeedsDetailPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const FeedsDetailView();
}
}
class FeedsDetailView extends StatelessWidget {
const FeedsDetailView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final String text1 = lorem(paragraphs: 2, words: 55);
final String text2 = lorem(paragraphs: 9, words: 500);
final String text3 = lorem(paragraphs: 10, words: 400);
final String text4 = lorem(paragraphs: 8, words: 2000);
final String text5 = lorem(paragraphs: 12, words: 500);
final textList = [
text3,
text4,
text5,
];
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Container(
child: Stack(
children: [
Positioned(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 368,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
//color: Colors.blue,
),
child: Assets.images.nightBuilding.image(
fit: BoxFit.cover,
),
),
),
),
Positioned(
top: 250,
left: 20,
child: Container(
height: 60,
width: 350,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Theme.of(context)
.backgroundColor
.computeLuminance() >
0.5
? Colors.black
: Colors.white,
),
child: AppMediumText(text: text1),
),
),
Positioned(
top: 334,
right: 33,
child: ElevatedButtonSmall(
onpressed: () {},
text: '',
useIcon: true,
icon: Icons.account_balance,
fizedSize: const Size(50, 50),
radius: 35,
),
),
Positioned(
top: 334,
right: 105,
child: ElevatedButtonSmall(
onpressed: () {},
text: '',
useIcon: true,
icon: Icons.text_fields,
fizedSize: const Size(50, 50),
radius: 35,
),
),
],
),
),
const SizedBox(height: 8),
Divider(
color: Theme.of(context).colorScheme.secondary,
indent: 50,
endIndent: 50,
),
Container(
width: 380,
child: PageView.builder(
itemCount: textList.length + 1,
itemBuilder: (context, index) {
if (index == 0) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 14),
Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: SizedBox(
width: 350,
child: AppSmallText(
text: text2.replaceFirst(
text2[0],
text2[0].toUpperCase(),
),
),
),
),
],
);
} else {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 14),
Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: SizedBox(
width: 350,
child: AppSmallText(
text: textList[index - 1].replaceFirst(
textList[0],
textList[0].toUpperCase(),
),
),
),
),
],
);
}
},
),
)
],
),
),
);
}
}

How can I provide a minimum height to ListView.builder's children which can expand automatically if the children require more space?

I am using ListView.builder. In this, I need to set heights for the individual children. As of now, I'm achieving this using a SizedBox, but this doesn't give me the effect I want.
This is important because some of the children are column widgets like this:
return Column(
children: List.generate( //using List.generate for building the UI
data.length, //I don't know this length beforehand
(int i) => Padding(
padding: EdgeInsets.only(
left: 30.0, right: 30.0, bottom: height * 0.05),
child: EducationMobileCard(
//contents here
),
),
),
);
I want to wrap all widgets like this in a parent ListView.builder. Such that, when the user scrolls, each widget takes up the space that is required to fit its contents. Wrapping the widgets in SizedBox doesn't handle overflows. I've tried ConstrainedBox too. But it doesn't let the other parts of the UI access the vacant screen in case a widget hasn't taken up the entire maxWidth. It just simply keeps the space vacant.
This is the ListView.builder widget I'm currently using:
ListView.builder(
itemCount: 7,
itemBuilder: (context, index) {
return SizedBox(height: height, child: widgetList[index]); //height is the screen height here
}
),
I simply want something that specifies the minimum space to occupy but lets the widget handle the maximum space to take within the ListView.builder.
Edit: This is the EducationMobileCard widget:
import 'package:flutter/material.dart';
import '../custom/text_style.dart';
import '../theme/config.dart';
class EducationMobileCard extends StatefulWidget {
const EducationMobileCard(
{Key? key,
//the required parameters
)
: super(key: key);
final double height, width;
final String insttution, location, years, grades, desc, image;
#override
_EducationMobileCardState createState() => _EducationMobileCardState();
}
class _EducationMobileCardState extends State<EducationMobileCard> {
bool isHover = false;
#override
Widget build(BuildContext context) {
return AnimatedContainer(
decoration: BoxDecoration(
boxShadow: [
//contents
],
),
duration: const Duration(milliseconds: 200),
padding: EdgeInsets.only(
top: isHover ? widget.height * 0.005 : widget.height * 0.01,
bottom: !isHover ? widget.height * 0.005 : widget.height * 0.01),
child: InkWell(
onTap: () {},
onHover: (bool value) {
setState(() {
isHover = value;
});
},
child: Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.only(
top: widget.height * 0.04,
left: widget.width * 0.015,
right: widget.width * 0.015,
bottom: widget.height * 0.04),
width: widget.width,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: isHover ? Colors.black12 : Colors.black45,
blurRadius: 10.0,
offset: const Offset(8, 12),
)
],
color: currentTheme.currentTheme == ThemeMode.dark
? Theme.of(context).cardColor
: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(
5.0,
),
),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 5.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.asset(
'assets/education/${widget.image}',
scale: 1.2,
)),
),
FittedBox(
fit: BoxFit.cover,
child: text(widget.insttution, 25, Colors.white)),
Padding(
padding: const EdgeInsets.only(bottom: 5.0),
child: FittedBox(
fit: BoxFit.cover,
child: text(widget.location, 10, Colors.white)),
),
FittedBox(
fit: BoxFit.cover,
child: Padding(
padding: const EdgeInsets.only(bottom: 11.0),
child: text(
widget.years != ''
? 'Years of study: ${widget.years}'
: '',
12,
Colors.white),
)),
FittedBox(
fit: BoxFit.cover,
child: text(widget.desc, 15, Colors.white)),
FittedBox(
fit: BoxFit.cover,
child: text(
widget.grades != ''
? 'Grades Achieved: ${widget.grades}'
: '',
12,
Colors.white)),
],
),
),
),
),
);
}
}
You can use ConstrainedBox to set the maxmium and minimum hight.
Refer the example below
ConstrainedBox(
constraints: new BoxConstraints(
minHeight: 35.0,
maxHeight: 160.0,
),
child: new ListView(
shrinkWrap: true,
children: <Widget>[
new ListItem(),
new ListItem(),
],
),
)
You can then use the shrinkWrap proper to wrap the unused space like this:-
shrinkWrap: true,
Thank you

How to clip one container over another in flutter?

I want to build a reusable card widget, it will have an image and text with some custom design layout. I tried everything I could, but wasn't able to achieve the desired result. Any help would be much appreciated.
This is what I want to do
I'm stuck here
This is my code
class ReusabelCard extends StatelessWidget {
ReusabelCard(
{this.cardChild, #required this.assetImagePath, #required this.cardText});
final Widget cardChild;
final String assetImagePath;
final String cardText;
#override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height * 0.35,
width: MediaQuery.of(context).size.width * 0.5,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(MediaQuery.of(context).size.width * 0.5 * 0.28),
),
child: Stack(
children: [
LayoutBuilder(
builder: (context, contraint) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Icon(
Icons.trip_origin,
size: contraint.biggest.width,
color: Colors.grey[300],
),
Container(
height: MediaQuery.of(context).size.height*0.05,
width: MediaQuery.of(context).size.width,
color: Colors.green,
),
],
);
},
),
],
)
);
}
}
Use ClipRRect to do it:
ClipRRect(
borderRadius: BorderRadius.circular(50.0), //clipping the whole widget
child: Container(
height: MediaQuery.of(context).size.height * 0.4, //I adjusted here for responsiveness problems on my device
width: MediaQuery.of(context).size.width * 0.5,
color: Colors.white,
child: LayoutBuilder(
builder: (context, constraint) {
return Stack(
children: [
Center(
child: Icon(
Icons.trip_origin,
size: constraint.biggest.width,
color: Colors.grey[300],
),
),
Positioned(
right: 0,
left: 0,
top: 20.0,
child: Icon(
Icons.sports_volleyball_rounded, //just to represent the ball
size: constraint.biggest.width * 0.5,
),
),
Positioned(
bottom: 0.0,
child: Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height * 0.1,
width: constraint.biggest.width,
color: Colors.yellow[700],
child: Text(
'Sports',
style: Theme.of(context)
.textTheme
.headline3
.copyWith(color: Colors.white),
),
),
),
],
);
},
),
),
);

Align Materials to same widths and heights without a Table

I created a material for my app which should enclose some text. It looks like this:
Sometimes, there is overflowing text. With a flexible it looks like this:
And I also want it to align like in a Table. Without alignment to the others it looks like this:
The Border between the colors should be at the same position for all of those elements so it looks clean.
How can I achieve all of this? The Flexible Widget throws a WrongParent Exception when Put into a Table.
My Code:
import 'dart:math';
import 'package:flutter/material.dart';
import 'nook_constants.dart';
class NookTable extends StatelessWidget {
final double width;
final double height;
final EdgeInsets margin;
final Widget child;
final String title;
final String text;
final String font;
NookTable({
this.width,
this.height,
this.margin: nookDefaultMargin,
this.child,
this.title,
this.text,
this.font
});
final cell = (Widget widget) => Padding(
padding: EdgeInsets.only(left: 15, top: 5, bottom: 5, right: 15),
child: widget,
);
#override
Widget build(BuildContext context) {
var margin = EdgeInsets.only(
left: this.margin?.left ?? 0.0,
right: this.margin?.right ?? 0.0,
top: this.margin?.top ?? 0.0,
bottom: max(2, this.margin?.bottom ?? 0.0),
);
return Container(
width: width,
height: height,
clipBehavior: Clip.antiAlias,
margin: EdgeInsets.only(left: 15, top: 5, bottom: 5, right: 15),
decoration: BoxDecoration(
color: Colors.transparent,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
NookTitleDetails(text: title, width: width,),
NookTextDetails(text: text,),
],
),
);
}
}
class NookTextDetails extends StatelessWidget {
final String text;
final String font;
NookTextDetails({
this.text,
this.font
});
final cell = (Widget widget) => Padding(
padding: EdgeInsets.only(left: 15, top: 5, bottom: 5, right: 15),
child: widget,
);
#override
Widget build(BuildContext context) {
return Flexible(
child: Material(
clipBehavior: Clip.antiAlias,
borderRadius: BorderRadius.only(bottomRight: Radius.circular(25), topRight: Radius.circular(25)),
color: nookBeige,
child: cell(Text(text))
),
);
}
}
class NookTitleDetails extends StatelessWidget {
final String text;
final String font;
final double width;
NookTitleDetails({
this.text,
this.font,
this.width
});
final cell = (Widget widget) => Padding(
padding: EdgeInsets.only(left: 15, top: 5, bottom: 5, right: 15),
child: widget,
);
#override
Widget build(BuildContext context) {
return Container(
width: width,
child: Material(
clipBehavior: Clip.antiAlias,
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(25), topLeft: Radius.circular(25)),
color: nooklightGreen,
child: cell(Text(text, style: TextStyle(color: nookWhite)))
),
);
}
}
Container(
decoration: BoxDecoration(
color: Colors.lime,
borderRadius: BorderRadius.all(Radius.circular(10))
),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 1,
child: Stack(
children: <Widget>[Container(
width: 100,
padding: EdgeInsets.all(5),
child: Text('Fundort',textAlign: TextAlign.center,))],
)),
Expanded(
flex: 4,
child: Container(
decoration: BoxDecoration(
color: Colors.lightGreen,
borderRadius: BorderRadius.horizontal(right:Radius.circular(10))
),
padding: EdgeInsets.all(10),
child: Text('Sign in with FacebookSign in with Facebook',
style: TextStyle(fontSize: 18, color: Colors.white)),
),
)
]),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 0,
child: Container(
width:100,
child:Text('Text to the left')
)
),
Expanded(
flex: 4,
child:Text('Text to the right')
),
],
),

flutter cannot acces a method of another class using static access

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)