I want to create a superellipse shape in Flutter for a widget.
I found an article about creating superellipses written in python and java, but i can't quite get the code to work.
Link to article
class SuperEllipse extends ShapeBorder {
final BorderSide side;
final double n;
SuperEllipse({
#required this.n,
this.side = BorderSide.none,
}) : assert(side != null);
#override
EdgeInsetsGeometry get dimensions => EdgeInsets.all(side.width);
#override
ShapeBorder scale(double t) {
return SuperEllipse(
side: side.scale(t),
n: n,
);
}
#override
Path getInnerPath(Rect rect, {TextDirection textDirection}) {
return _superEllipsePath(rect, n);
}
#override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
return _superEllipsePath(rect, n);
}
static Path _superEllipsePath(Rect rect, double n) {
final int a = 200;
List<double> points = [a + 1.0];
Path path = new Path();
path.moveTo(a.toDouble(), 0);
// Calculate first quadrant.
for (int x = a; x >= 0; x--) {
points[x] = pow(pow(a, n) - pow(x, n), 1 / n);
path.lineTo(x.toDouble(), -points[x]);
}
// Mirror to other quadrants.
for (int x = 0; x <= a; x++) {
path.lineTo(x.toDouble(), points[x]);
}
for (int x = a; x >= 0; x--) {
path.lineTo(-x.toDouble(), points[x]);
}
for (int x = 0; x <= a; x++) {
path.lineTo(-x.toDouble(), -points[x]);
}
return path;
}
#override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
Path path = getOuterPath(rect.deflate(side.width / 2.0), textDirection: textDirection);
canvas.drawPath(path, side.toPaint());
}
}
I want to return the correct shape, but instead I get an Exception: Invalid value: Only valid value is 0: 200.
For some reason the variable a isn't allowed to be 200? I don't know why, and changing it to 0 doesn't produce any errors, but then there is no shape either.
Does anyone know if there is a better way of doing this?
there is a class for this in flutter, it is called ContinuousRectangleBorder.
Material(
color: Colors.red,
shape: ContinuousRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
child: Container(
padding: EdgeInsets.all(40,0),
margin: EdgeInsets.all(8.0),
child: Center(child: Text('Hello World')),
),
)
you can also use it directly in container with decoration: ShapeDecoration(shape: ContinuousRectangleBorder())
Container(
decoration: ShapeDecoration(
color: Colors.red,
shape: ContinuousRectangleBorder(
borderRadius: BorderRadius.circular(70.0),
),
),
padding: EdgeInsets.fromLTRB(10, 40, 10, 40),
// margin: EdgeInsets.all(8.0),
child: Center(child: Text('Hello World')),
)
came across this package that produces squircles
https://pub.dev/packages/cupertino_rounded_corners
i'm sure you can dig around the code to find out how it makes the shape
Related
I made this notes app which uses firestore to save data and it is working fine, no problem whatsoever.
Now I am trying to implement a search filter on notes and I can't find the right method to do it.
Here is my code that renders the notes on the screen
here is the reference image
List<Widget> _buildNotesView(
BuildContext context, NoteFilter filter, List<Note> notes) {
if (notes?.isNotEmpty != true) {
return [_buildBlankView(filter.noteState)];
}
final asGrid = filter.noteState == NoteState.deleted || notesView;
final factory = asGrid ? NotesGrid.create : NotesList.create;
final showPinned = filter.noteState == NoteState.unspecified;
if (!showPinned) {
return [
factory(notes: notes, onTap: _onNoteTap),
];
}
final partition = _partitionNotes(notes);
final hasPinned = partition.item1.isNotEmpty;
final hasUnpinned = partition.item2.isNotEmpty;
final _buildLabel = (String label, [double top = 26]) => SliverToBoxAdapter(
child: Container(
padding:
EdgeInsetsDirectional.only(start: 26, bottom: 25, top: top),
child: Text(
label,
style: TextStyle(
fontFamily: selectedFont,
color: kHintTextColorLight,
fontWeight: FontWeights.medium,
fontSize: 12,
),
),
),
);
//TODO
if (searchController.text.isNotEmpty) {
notes.forEach((note) {
if (note.title
.toLowerCase()
.contains(searchController.text.toLowerCase()) ||
note.content
.toLowerCase()
.contains(searchController.text.toLowerCase())) ;
//Do something here?
});
}
return [
if (hasPinned) _buildLabel('PINNED', 0),
if (hasPinned) factory(notes: partition.item1, onTap: _onNoteTap),
if (hasPinned && hasUnpinned) _buildLabel('OTHERS'),
factory(notes: partition.item2, onTap: _onNoteTap),
];
}
Any help would be great. I'm open to learning.
How do I loop over my Dic keys on a slider? the slider behaivior is dividing the first key by the last key. what I want is only to loop throgh the keys value then somehow return the value's value...
struct ContentView: View {
#State private var currentValue = 0.0
#ObservedObject var scoreModel = ScoreModel()
var body: some View {
let endValue = Dictionary(uniqueKeysWithValues:
scoreModel.eventMDL.map { key, value in (key, value) })
return VStack {
Slider(value: $currentValue, in: endValue.keys.sorted()[1]...endValue.keys.sorted()[27])
.rotationEffect(Angle(degrees: -90))
Spacer()
Text("\(currentValue, specifier: "%.0f")")
}
.frame(height: 280)
}
}
The model:
#Published var eventMDL = [340.0: 100.0,
330.0: 97.0,
320.0: 94.0,
310.0: 92.0,
300.0: 90.0,
290.0: 88.0,
280.0: 86.0,
270.0: 84.0,
260.0: 82.0,
250.0: 80.0,
240.0: 78.0,
230.0: 76.0,
220.0: 74.0,
210.0: 72.0,
200.0: 70.0,
190.0: 68.0,
180.0: 65.0,
170.0: 64.0,
160.0: 63.0,
150.0: 62.0,
140.0: 60.0,
130.0: 50.0,
120.0: 40.0,
110.0: 30.0,
100.0: 20.0,
90.0: 10.0,
80.0: 0.0,
0.0 : 0.0]
First, I'd recommend creating an array with your keys and sort it. As you already use a #Published property I added updating this array in didSet:
class ScoreModel: ObservableObject {
#Published var eventMDL = [
340.0: 100.0,
...
0.0: 0.0,
] {
didSet {
eventMDLKeysSorted = eventMDL.keys.reversed().sorted()
}
}
lazy var eventMDLKeysSorted: [Double] = eventMDL.keys.reversed().sorted()
}
However, if the eventMDL dictionary is assigned only once, there's no need for it to be #Published:
class ScoreModel: ObservableObject {
let eventMDL = [
340.0: 100.0,
...
0.0: 0.0,
]
lazy var eventMDLKeysSorted: [Double] = eventMDL.keys.reversed().sorted()
}
Then keep track of current key instead of value:
#State private var currentKey = 0.0
Then create a range:
var firstKey: Double {
scoreModel.eventMDLKeysSorted[1]
}
var lastKey: Double {
scoreModel.eventMDLKeysSorted[scoreModel.eventMDLKeysSorted.count - 1]
}
and set it for the Slider adding a step of 10 (the difference between the subsequent keys):
Slider(value: $currentKey, in: firstKey...lastKey, step: 10)
Then we access the current value:
var currentValue: Double {
scoreModel.eventMDL[currentKey]!
// or provide a default value
// or make currentValue optional
}
Summing up this is how your ContentView might look like:
struct ContentView: View {
#ObservedObject var scoreModel = ScoreModel()
#State private var currentKey = 0.0
var firstKey: Double {
scoreModel.eventMDLKeysSorted[1]
}
var lastKey: Double {
scoreModel.eventMDLKeysSorted[scoreModel.eventMDLKeysSorted.count - 1]
}
var currentValue: Double {
return scoreModel.eventMDL[currentKey]!
}
var body: some View {
VStack {
Slider(value: $currentKey, in: firstKey...lastKey, step: 10)
.rotationEffect(Angle(degrees: -90))
Spacer()
Text("\(currentValue, specifier: "%.0f")")
}
.frame(height: 280)
}
}
Also you may want to set the Slider's start position:
init() {
_currentKey = .init(initialValue: scoreModel.eventMDLKeysSorted[1])
}
i am creating a flutter app where the user has a canvas which he can draw on and then he can save the canvas to Firestore and can recall and edit whenever he wants.I have seen tutorials in creating a canvas and drawing on it but i dont know how to save it to firebase, i have seen some say to convert it as an image and save it to firebase storage but after saving it as an image can the user recall and edit it , and is it possible to save all the points the user has drawn on canvas in the form of a list
Below is a code i am working on,
In this i am trying to save all the points in a list and update it to firebase
class _HomePageState extends State<HomePage> {
List<Offset> _points = <Offset>[];
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Container(
child: new GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
setState(() {
RenderBox object = context.findRenderObject();
Offset _localPosition =
object.globalToLocal(details.globalPosition);
_points = new List.from(_points)..add(_localPosition);
});
},
onPanEnd: (DragEndDetails details) => _points.add(null),
child: new CustomPaint(
painter: new Signature(points: _points),
size: Size.infinite,
),
),
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.save),
onPressed: () => Firestore.instance.collection('points').document('XcX3MbUWt3hiBJyiPMIO'
).updateData({'points':FieldValue.arrayUnion(_points)})
),
);
}
}
class Signature extends CustomPainter {
List<Offset> points;
Signature({this.points});
#override
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
..color = Colors.blue
..strokeCap = StrokeCap.round
..strokeWidth = 10.0;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null) {
canvas.drawLine(points[i], points[i + 1], paint);
}
}
}
#override
bool shouldRepaint(Signature oldDelegate) => oldDelegate.points != points;
}
It gives an error
Unhandled Exception: Invalid argument: Instance of 'Offset'
Is this method of saving possible of so how to do
I am able to print the offsets of the canvas
So I'm trying to display a pie chart using the fl_chart plugin. The data for the chart is being retrieved from firestore. I have this function that is used to display the data:
List<PieChartSectionData> showSection(AsyncSnapshot<QuerySnapshot> snapshot) {
return List.generate(length, (i) {
final isTouched = i == touchedIndex;
final double fontSize = isTouched ? 25 : 16;
final double radius = isTouched ? 60 : 50;
return PieChartSectionData(
color: Color(int.parse(cerealData[i].colorVal)),
value: cerealData[i].rating,
title: cerealData[i].rating.toString(),
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
);
});
}
The List.generate() takes an int as an argument. Since I'm displaying realtime data, I'm trying to get the number of documents present in my collection. For that, I have a function called getLength():
void getLength(AsyncSnapshot<QuerySnapshot> snapshot) async {
length = await Firestore.instance.collection('cereal').snapshots().length;
cerealData =
snapshot.data.documents.map((e) => Cereal.fromJson(e.data)).toList();
}
However, when I run the code, I get:
Another exception was thrown: type 'Future<int>' is not a subtype of type 'int'
The entire code:
class _FlChartPageState extends State<FlChartPage> {
int touchedIndex;
var length;
List<Cereal> cerealData;
void getLength(AsyncSnapshot<QuerySnapshot> snapshot) async {
length = await Firestore.instance.collection('cereal').snapshots().length;
cerealData =
snapshot.data.documents.map((e) => Cereal.fromJson(e.data)).toList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('cereal').snapshots(),
builder: (context, snapshot) {
getLength(snapshot);
if (!snapshot.hasData)
return CircularProgressIndicator();
else {
return PieChart(PieChartData(
pieTouchData: PieTouchData(touchCallback: (pieTouchResponse) {
setState(() {
if (pieTouchResponse.touchInput is FlLongPressEnd ||
pieTouchResponse.touchInput is FlPanEnd) {
touchedIndex = -1;
} else {
touchedIndex = pieTouchResponse.touchedSectionIndex;
}
});
}),
borderData: FlBorderData(show: false),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: showSection(snapshot)));
}
}),
);
}
List<PieChartSectionData> showSection(AsyncSnapshot<QuerySnapshot> snapshot) {
return List.generate(length, (i) {
final isTouched = i == touchedIndex;
final double fontSize = isTouched ? 25 : 16;
final double radius = isTouched ? 60 : 50;
return PieChartSectionData(
color: Color(int.parse(cerealData[i].colorVal)),
value: cerealData[i].rating,
title: cerealData[i].rating.toString(),
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
);
});
}
}
I read somewhere that awaiting the future gets rid of the Future. But that doesn't work here.
How do I fix this?
Edit: It works if I simply pass the number of documents instead of length in List.generate(). But this won't work if there are changes to the collection. So how do I convert Future to int?
I think you aren't getting the length of the documents, you are getting the length of the snapshots if you want to get the documents length :
QuerySnapshot querySnapshot = await Firestore.instance.collection('cereal').getDocuments();
int length = querySnapshot.documents.length;
In get getLength function you are trying to get length which is actually async task which returns future and because of that you are getting following error.
Change your method with following metod
getLength()async{
Firestore.instance.collection('cereal').snapshots().length.then((len){
length = len;
cerealData =
snapshot.data.documents.map((e) => Cereal.fromJson(e.data)).toList();
});
}
I'm trying to get data from Firestore, in debug print the future does it job and list gets data and in debugPrint length is +, but when I try to get data in another Widget list recives null, in debugPrint length is 0 .
model.dart
class BBModel extends Model {
int _counter = 10;
int get counter => _counter;
var db = dbBB;
List<BB> _bbs;
List<BB> get bbs => _bbs;
Future<List<BB>> getBBs() async {
var snapshot = await db.getDocuments();
for (int i = 0; i < snapshot.documents.length; i++) {
_bbs.add(BB.fromSnapshot(snapshot.documents[i]));
print(bbs.length.toString()); //recives 23
}
notifyListeners();
return _bbs;
}
}
main.dart
void main() {
var model = BBModel();
model.getBBs();
runApp(ScopedModel<BBModel>(model: BBModel(), child: MyApp()));
}
statefullpage.dart
Expanded(
flex: 1,
child: Container(
height: 400.0,
child: ScopedModelDescendant<BBModel>(
builder: (context, child, model) {
return ListView.builder(
itemCount: model.bbs.length,
itemBuilder: (context, index) {
return Text(model.bbs[index].bbID);
});
}))),
Looks like the code you're written in main.dart is wrong. The instatiated model is different from the one you've sent in your ScopedModel.
Correction
Change model: model to model: BBModel() in your main.dart file.
void main() {
final model = BBModel();
model.getBBs();
runApp(ScopedModel<BBModel>(model: model, child: MyApp()));
}
In main.dart, I would try doing:
void main() {
var model = BBModel();
model.getBBs().then((someVariableName){
runApp(ScopedModel<BBModel>(model: BBModel(), child: MyApp()));
});
}
note: "someVariableName" will contain a List< BB>
To wait you can use the
await model.getBBs();
Apart from this however, I do not recommend uploading data to the main, as you would slow down the use of the app, as the data is getting bigger. Upload the data only to the pages you need and find a way to do this.