Why red lines painted? - flutter

I expected size to be a child widget's size, and the result to be a whole black screen.
But it seems not. My _TestBox doesn't cover all child area. Why this happens?
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: HomePage());
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 300),
_TestBox(
child: Container(width: 200, height: 200, color: Colors.red),
),
SizedBox(height: 800),
],
),
));
}
}
#immutable
class _TestBox extends SingleChildRenderObjectWidget {
const _TestBox({Widget? child}) : super(child: child);
#override
_TestFilter createRenderObject(BuildContext context) {
return _TestFilter();
}
#override
void updateRenderObject(BuildContext context, _TestFilter filter) {
filter.markNeedsPaint();
}
}
class _TestFilter extends RenderProxyBox {
#override
ShaderMaskLayer? get layer => super.layer as ShaderMaskLayer?;
#override
bool get alwaysNeedsCompositing => child != null;
#override
void paint(PaintingContext context, Offset offset) {
if (child != null) {
assert(needsCompositing);
const color = Colors.black;
layer ??= ShaderMaskLayer();
layer!
..shader = LinearGradient(
colors: [color, color],
).createShader(Rect.fromLTWH(0, 0, 1, 1))
..maskRect = offset & size
// The following has no problem.
// ..maskRect = (offset & size).inflate(1)
..blendMode = BlendMode.srcIn;
context.pushLayer(layer!, super.paint, offset);
} else {
layer = null;
}
}
}

It came out as device specific issue.

Related

Dart: Reading a specific line in a text based on a keyword

I have this line of text that is as follows:
IMEI
IMEII :869425035089513
IME12:869425035100520
SN:3ST0218A22000432
I want to only get the 2nd line of text that is "IMEII :869425035089513" but remove the rest. How shall I do that in Dart?
try this
var str = "IMEI"
IMEII :869425035089513
IME12:869425035100520
SN:3ST0218A22000432";
var parts = str.split('\n');
print(parts[0]);
print(parts[1]);// print 2nd Line data
When you enter a string in the text field, only the strings that contain the entered string are displayed.
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
//data
List<String> _list = [
'IMEI',
'IMEII :869425035089513',
'IME12:869425035100520',
'SN:3ST0218A22000432'
];
//show data
List<String> _data = [];
#override
Widget build(BuildContext context) {
Size _size = MediaQuery.of(context).size;
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_textFiled(_size),
for (int i = 0; i < _data.length; i++)
_showData(_size, i),
],
),
),
),
);
}
//TextFiled Widget
Widget _textFiled(Size size) {
return Container(
width: size.width,
height: size.height * 0.1,
child: TextField(
decoration: InputDecoration(
labelText: 'Text',
),
onChanged: (String text) {
_data.clear();
setState(() {
if (text.isEmpty) {
_data = _list.toList();
} else {
for (int i = 0; i < _list.length; i++) {
if (_list[i].contains(text)) {
_data.add(_list[i].toString());
}
}
}
});
},
),
);
}
//show Data
Widget _showData(Size size, int index) {
return Container(
width: size.width,
height: size.height * 0.05,
child: Text('${_data[index]}'),
);
}
}
You can use contain() which is a string comparison.

CustomPaint designs one below another in Flutter

I am trying to build a website using flutter and I want it's background to have a wavy corner with a different color at one end. I need four blocks in this designs i.e. as you scroll you'll reveal new blocks, and the height of each block should be the same as the height of the screen.
So, I thought of using CustomPaint to do it so I started to implement it but I am getting around 500 lines of error messages and it's not working.
I'm new to flutter so I don't know if I've implemented everything the way it should be implemented. I've shared all the code down below:
main.dart
import 'package:flutter/material.dart';
import 'blocks/block1.dart';
import 'blocks/block2.dart';
import 'blocks/block3.dart';
import 'blocks/block4.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
BlockOne(),
//BlockTwo(),
//BlockThree(),
//BlockFour()
],
),
)
);
}
}
block1.dart - block 2, 3 and 4 are almost similar:
Note- I've not added the wavy pattern in this code below because this itself is not working
import 'package:flutter/material.dart';
class BlockOne extends StatefulWidget {
#override
_BlockOneState createState() => _BlockOneState();
}
class _BlockOneState extends State<BlockOne> {
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 1024)
return Desktop();
else
return Mobile();
},
);
}
}
class Desktop extends StatefulWidget {
#override
_DesktopState createState() => _DesktopState();
}
class _DesktopState extends State<Desktop> {
#override
Widget build(BuildContext context) {
return Container(
child: Text('Desktop'),
);
}
}
class Mobile extends StatefulWidget {
#override
_MobileState createState() => _MobileState();
}
class _MobileState extends State<Mobile> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomPaint(
size: const Size(double.infinity, double.infinity),
painter: MobilePainter(),
),
);
}
}
class MobilePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final height = size.height;
final width = size.width;
Paint paint = Paint();
paint.color = Colors.black;
Path background = Path();
background.addRect(Rect.fromLTRB(0, 0, width, height));
canvas.drawPath(background, paint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return oldDelegate != this;
}
}
Check the following. Here I am using a list view to show contents. In flutter it is important to understand the concept that constraints go down from parent to child and the size goes up from a child to parent.
Here is demo of how this can be achieved. dartpad demo
If the child doesn't define a size then in ListView you have to define the itemExtent.
import 'package:flutter/material.dart';
// import 'blocks/block1.dart';
// import 'blocks/block2.dart';
// import 'blocks/block3.dart';
// import 'blocks/block4.dart';
void main() {
runApp(ScrollableView());
}
class ScrollableView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
// child: Column(
shrinkWrap: true,
itemExtent: 200,
children: <Widget>[
BlockOne(),
Container(
color: Colors.black,
),
BlockOne(),
Text('Hello'),
BlockOne(),
Container(
color: Colors.black,
),
BlockOne(),
//BlockTwo(),
//BlockThree(),
//BlockFour()
],
// ),
));
}
}
class BlockOne extends StatefulWidget {
#override
_BlockOneState createState() => _BlockOneState();
}
class _BlockOneState extends State<BlockOne> {
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
// if (constraints.maxWidth > 1024)
// return Desktop();
// else
return Mobile();
},
);
}
}
class Desktop extends StatefulWidget {
#override
_DesktopState createState() => _DesktopState();
}
class _DesktopState extends State<Desktop> {
#override
Widget build(BuildContext context) {
return Container(
child: Text('Desktop'),
);
}
}
class Mobile extends StatefulWidget {
#override
_MobileState createState() => _MobileState();
}
class _MobileState extends State<Mobile> {
#override
Widget build(BuildContext context) {
return CustomPaint(
size: const Size(double.infinity, double.infinity),
painter: MobilePainter(),
);
}
}
class MobilePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final height = size.height;
final width = size.width;
Paint paint = Paint();
paint.color = Colors.green;
Path background = Path();
background.addRect(Rect.fromLTRB(0, 0, width, height));
canvas.drawPath(background, paint);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return oldDelegate != this;
}
}

Is there a way to call a method of a stateless widget to another stateless widget?

Here, I have two files dot_indicator.dart and main.dart.
The function which is inside the Dots class "updatePosition()", how can it be accessed inside the onPageChanged of the PageView widget.
import 'package:flutter/material.dart';
import 'package:dots_indicator/dots_indicator.dart';
class Dots extends StatefulWidget {
#override
_DotsState createState() => _DotsState();
}
class _DotsState extends State<Dots> {
final _totalDots = 2;
double currentPosition = 0.0;
double validPosition(double position) {
if (position >= _totalDots) return 0;
if (position < 0) return _totalDots - 1.0;
return position;
}
void updatePosition(double position) {
setState(() => currentPosition = validPosition(position));
}
String getCurrentPositionPretty() {
return (currentPosition + 1.0).toStringAsPrecision(2);
}
#override
Widget build(BuildContext context) {
return DotsIndicator(
dotsCount: _totalDots,
position: currentPosition,
decorator: DotsDecorator(
activeColor: Colors.green,
activeSize: Size.square(30.0),
activeShape: RoundedRectangleBorder(),
),
);
}
}
This widget had the function updatePosition(index), I want to access it in another class.
import 'package:flutter/material.dart';
import 'package:mobile_app/bottom_nav.dart';
import 'package:mobile_app/dot_indicator.dart';
import 'package:mobile_app/first_page.dart';
import 'package:mobile_app/second_page.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
backgroundColor: Color.fromRGBO(250, 250, 250, 100),
elevation: 0.0,
title: Stack(
children: <Widget>[
Container(
width: double.infinity,
child: Dots(),
),
],
),
),
body: PageSlider(),
bottomNavigationBar: AppBottomNav(),
),
);
}
}
class PageSlider extends StatefulWidget {
const PageSlider({Key? key}) : super(key: key);
#override
_PageSliderState createState() => _PageSliderState();
}
class _PageSliderState extends State<PageSlider> {
Dots _dots = new Dots();
#override
Widget build(BuildContext context) {
PageController controller = PageController(initialPage: 0, keepPage: true);
return PageView(
controller: controller,
onPageChanged: (index) => {
print(index),
//I want the updatePosition(index) here
},
children: <Widget>[
FirstPage(),
SecondPage(),
],
);
}
}
I tried making the instance of the Dots class and tried to use it inside the PageSlider class, it still wont work.

flutter: CustomPaint widget turned blank when put in a Column

I've got something super bizarre:
The following code paints a rectangle with CustomPaint. This version works fine
import 'package:flutter/material.dart';
class MyApp extends StatefulWidget {
#override
_ MyAppState createState() => _ MyAppState();
}
class _MyAppState extends State<MyApp> {
EmbeddedPainter _painter;
#override
void initState() {
super.initState();
_painter = EmbeddedPainter();
}
#override
Widget build(BuildContext context) {
return Container(
child: ClipRect(
child: CustomPaint(
painter: _painter
),
),
);
}
}
Then as soon as I place this CustomPaint into a Column widget, I no longer see the painted rectangle.
import 'package:flutter/material.dart';
class MyApp extends StatefulWidget {
#override
_ MyAppState createState() => _ MyAppState();
}
class _MyAppState extends State<MyApp> {
EmbeddedPainter _painter;
#override
void initState() {
super.initState();
_painter = EmbeddedPainter();
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
ClipRect(
child: CustomPaint(
painter: _painter
),
),
],
)
);
}
}
The painter looks like this
class EmbeddedPainter extends CustomPainter with ChangeNotifier {
var _paint = Paint()
..strokeJoin = StrokeJoin.miter
..strokeWidth = 1.0
..color = Colors.green
..style = PaintingStyle.fill;
#override
void paint(Canvas canvas, Size size) {
canvas.drawRect(Rect.fromLTWH(50, 50, 100, 100), _paint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
void update(Color color0, Color color1) {
// draw
notifyListeners();
}
}
Solved it myself:
The ClipRect must be wrapped with a container with size, e.g., a SizedBox.
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
SizedBox(
width: 500,
height: 300,
child: ClipRect(
child: CustomPaint(
painter: _painter
),
),
)
],
)
);
}

Call a setState of a statefull widget from the stateless widget

I have a stateless widget class that has a widget whose movements need to be tracked. I cannot keep this widget inside the stateful widgets as I don't want the state of this widget to be refreshed.
I have the following code.
import 'package:flutter/material.dart';
import 'package:control_pad/control_pad.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Column(
children: <Widget>[
Expanded(
child: JoystickView(
onDirectionChanged: (degree, direction) {
//Change the state here.
},
),
),
Expanded(
child: MyStateFull(),
),
],
),
);
}
}
class MyStateFull extends StatefulWidget {
#override
_MyStateFullState createState() => _MyStateFullState();
}
class _MyStateFullState extends State<MyStateFull> {
double degree = 10;
double direction = 10;
//Call this from the stateless Widget
void changedDirection(degree, direction) {
setState(() {
this.degree = degree;
this.direction = direction;
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Text(
"The degree Moved is $degree and the direction is $direction",
style: TextStyle(fontSize: 25, color: Colors.black),
),
);
}
}
This code produces the following output.
I want the direction and degree values to be changed as the joystick is moved.
Thank You.
I tried it myself and found the solution. This can be done using streams. I will post the code just in case someone needs it in the future.
import 'package:flutter/material.dart';
import 'package:control_pad/control_pad.dart';
class MyStateLess extends StatelessWidget {
StreamController<List<double>> _controller = StreamController<List<double>>();
GlobalKey<_MyStateFullState> statefulKey = new GlobalKey<_MyStateFullState>();
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
JoystickView(
onDirectionChanged: (degree, direction) {
List<double> temp = new List<double>();
temp.add(degree);
temp.add(direction);
_controller.add(temp);
},
),
MyStateFull(stream: _controller.stream, key: statefulKey),
],
);
}
}
class MyStateFull extends StatefulWidget {
final Stream<List<double>> stream;
MyStateFull({Key key, #required this.stream}) : super(key: key);
#override
_MyStateFullState createState() => _MyStateFullState();
}
class _MyStateFullState extends State<MyStateFull> {
double _degree = 0.0;
double _direction = 0.0;
#override
void initState() {
super.initState();
widget.stream.listen((event) {
setState(() {
_degree = event[0];
_direction = event[1];
});
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Text("$_degree, $_direction"),
);
}
}