I'm making a drawing app by Flutter. I can draw a line normally when i put it in a Scaffold with only home. But the problem is when i add an AppBar, the line is offset down from the top, it's not the position where i touch in screen, it's moved down same as the height of App BAr.
Here's my code.
class HiraganaWriting extends StatefulWidget {
const HiraganaWriting({Key? key}) : super(key: key);
@override
State<HiraganaWriting> createState() => _HiraganaWritingState();
}
class _HiraganaWritingState extends State<HiraganaWriting> {
final GlobalKey _globalKey = GlobalKey();
List<DrawnLine> lines = <DrawnLine>[];
DrawnLine line = DrawnLine([Offset(50, 50)], Colors.black, 5.0);
Color selectedColor = Colors.black;
double selectedWidth = 5.0;
StreamController<List<DrawnLine>> linesStreamController = StreamController<List<DrawnLine>>.broadcast();
StreamController<DrawnLine> currentLineStreamController = StreamController<DrawnLine>.broadcast();
String picName = "Hi";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("AppBar"),
),
body: Container(
child: Stack(
children: [
buildAllPaths(context),
buildCurrentPath(context),
],
),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.arrow_back), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.arrow_back), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.arrow_back), label: ""),
BottomNavigationBarItem(icon: Icon(Icons.arrow_back), label: ""),
],
),
);
}
Widget buildAllPaths(BuildContext context) {
return RepaintBoundary(
key: _globalKey,
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.transparent,
padding: EdgeInsets.all(4),
alignment: Alignment.topLeft,
child: StreamBuilder<List<DrawnLine>>(
stream: linesStreamController.stream,
builder: (context, snapshot) {
return CustomPaint(
painter: Sketcher(
lines: lines,
),
);
},
),
),
);
}
Widget buildCurrentPath(BuildContext context) {
return GestureDetector(
onPanStart: onPanStart,
onPanUpdate: onPanUpdate,
onPanEnd: onPanEnd,
child: RepaintBoundary(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
padding: EdgeInsets.all(4),
color: Colors.transparent,
alignment: Alignment.topLeft,
child: StreamBuilder<DrawnLine>(
stream: currentLineStreamController.stream,
builder: (context, snapshot) {
return CustomPaint(
painter: Sketcher(
lines: [line],
),
);
},
),
),
),
);
}
void onPanStart(DragStartDetails details) {
RenderBox? box = context.findRenderObject() as RenderBox?;
Offset point = box!.globalToLocal(details.globalPosition);
line = DrawnLine([point], selectedColor, selectedWidth);
}
void onPanUpdate(DragUpdateDetails details) {
RenderBox? box = context.findRenderObject() as RenderBox?;
Offset point = box!.globalToLocal(details.globalPosition);
List<Offset> path = List.from(line.path)..add(point);
line = DrawnLine(path, selectedColor, selectedWidth);
currentLineStreamController.add(line);
}
void onPanEnd(DragEndDetails details) {
lines = List.from(lines)..add(line);
linesStreamController.add(lines);
}
}
I tried to change padding, or put Container in of sizebox,.... but it's working wrongly
Don't use the scaffold inside HiraganaWriting
Widget, this widget is the painting part of application, just seperate this widget from scaffold.
HiraganaWriting
:
class HiraganaWriting extends StatefulWidget {
const HiraganaWriting({Key? key}) : super(key: key);
@override
State<HiraganaWriting> createState() => _HiraganaWritingState();
}
class _HiraganaWritingState extends State<HiraganaWriting> {
final GlobalKey _globalKey = GlobalKey();
List<DrawnLine> lines = <DrawnLine>[];
DrawnLine line = DrawnLine([Offset(50, 50)], Colors.black, 5.0);
Color selectedColor = Colors.black;
double selectedWidth = 5.0;
StreamController<List<DrawnLine>> linesStreamController =
StreamController<List<DrawnLine>>.broadcast();
StreamController<DrawnLine> currentLineStreamController =
StreamController<DrawnLine>.broadcast();
String picName = "Hi";
@override
Widget build(BuildContext context) {
return Stack(
children: [
buildAllPaths(context),
buildCurrentPath(context),
],
);
}
Widget buildAllPaths(BuildContext context) {
return RepaintBoundary(
key: _globalKey,
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.transparent,
padding: EdgeInsets.all(4),
alignment: Alignment.topLeft,
child: StreamBuilder<List<DrawnLine>>(
stream: linesStreamController.stream,
builder: (context, snapshot) {
return CustomPaint(
painter: Sketcher(
lines: lines,
),
);
},
),
),
);
}
Widget buildCurrentPath(BuildContext context) {
return GestureDetector(
onPanStart: onPanStart,
onPanUpdate: onPanUpdate,
onPanEnd: onPanEnd,
child: RepaintBoundary(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
padding: EdgeInsets.all(4),
color: Colors.transparent,
alignment: Alignment.topLeft,
child: StreamBuilder<DrawnLine>(
stream: currentLineStreamController.stream,
builder: (context, snapshot) {
return CustomPaint(
painter: Sketcher(
lines: [line],
),
);
},
),
),
),
);
}
void onPanStart(DragStartDetails details) {
RenderBox? box = context.findRenderObject() as RenderBox?;
Offset point = box!.globalToLocal(details.globalPosition);
line = DrawnLine([point], selectedColor, selectedWidth);
}
void onPanUpdate(DragUpdateDetails details) {
RenderBox? box = context.findRenderObject() as RenderBox?;
Offset point = box!.globalToLocal(details.globalPosition);
List<Offset> path = List.from(line.path)..add(point);
line = DrawnLine(path, selectedColor, selectedWidth);
currentLineStreamController.add(line);
}
void onPanEnd(DragEndDetails details) {
lines = List.from(lines)..add(line);
linesStreamController.add(lines);
}
}
Then use it in your page Widget like this:
class TestPage extends StatelessWidget {
const TestPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("AppBar"),
),
body: const HiraganaWriting());
}
}