I want to show some widget onTap() event over screen like below image .
Here is my code
In this the build method is return Container().
Container has one child named SingleChildScrollView and also it has some children.
So I don't want to change on this all children when new widget will create.
In simple, saw widget onTap() over the running screen without disturb another widget.
class _SettingScreenState extends State<SettingScreen> {
List<Widget> _iconList=[];
List<Widget> _titleList=[];
List<Widget> _settingLIst=[];
#override
void initState() {
super.initState();
for(int i=0;i<5;i++){
_iconList.add(_addInIcon(i));
}
for(int i=0;i<5;i++){
_titleList.add(_addInTitle(i));
}
for(int i=0;i<24;i++){
_settingLIst.add(_addInSetting(i));
}
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white
),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
_titleList[0],
_addInSetting(0),
_addInSetting(1),
_titleList[1],
_settingLIst[2],
_settingLIst[3],
_titleList[2],
_settingLIst[4],
_settingLIst[5],
_settingLIst[6],
_settingLIst[7],
_settingLIst[8],
_settingLIst[9],
GestureDetector(
onTap: (){
//open widget over the this screen
},
child: Button(
image: _coverImage(),
width: double.infinity,
height: 50,
alignment: Alignment.center,
fit: BoxFit.fitHeight,
),
),
],
),
),
);
}
}
Ans , is setState() is necessary while create new widget over the previous Container() widget ?
Because we cant change anything on previous Container()
In Android-java development, what i did
onClick()
{
ImageView imageView = new ImageView(this);
Glide.with(getApplicationContext()).load(position).into(imageView);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( Math.round((float) 35 * density), Math.round((float) 35 * density));
imageView.setX(reactionButton.getX());
imageView.setY(reactionButton.getY());
imageView.setLayoutParams(layoutParams);
messageRelativeLayout.addView(imageView);
imageView.bringToFront();
animateReaction(imageView);
}
It means every time new ImageView will added on tree, no matter if previous ImageView is appear or not.
Simple click button and create new ImageView and show front of screen.
this feature i want to apply in flutter
Child of OverlayWidget
class OverlayChild extends StatefulWidget {
final Function clearCallBack;
final double maxWidth;
final double maxHeight;
final int itemIndex;
const OverlayChild({
Key? key,
required this.clearCallBack,
required this.maxWidth,
required this.maxHeight,
required this.itemIndex,
}) : super(key: key);
#override
_OverlayChildState createState() => _OverlayChildState();
}
class _OverlayChildState extends State<OverlayChild> {
late Timer timer;
final Random random = Random();
#override
void initState() {
super.initState();
print("int ${widget.itemIndex}");
timer = Timer.periodic(Duration(seconds: 5), (timer) {
setState(() {
widget.clearCallBack(widget.itemIndex);
timer.cancel();
print("after delay");
});
});
}
#override
void dispose() {
timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Positioned(
top: random.nextDouble() * widget.maxHeight,
left: random.nextDouble() * widget.maxWidth,
child: Container(
height: 20,
width: 20,
padding: EdgeInsets.all(3),
decoration: BoxDecoration(
shape: BoxShape.circle,
color:
widget.itemIndex.isEven ? Colors.deepPurple : Colors.cyanAccent,
),
child: Center(child: Text("${widget.itemIndex}")),
),
);
}
}
Main Widget
class HomeOverLay extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<HomeOverLay> {
List<OverlayChild> overlayItems = [];
int itemId = 0;
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) => Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () async {
setState(() {
overlayItems.add(
OverlayChild(
key: UniqueKey(),
clearCallBack: (id) {
setState(() {
overlayItems
.removeWhere((element) => element.itemIndex == id);
});
},
itemIndex: itemId,
//same as container height
maxHeight: constraints.maxHeight * .1,
maxWidth: constraints.maxWidth,
),
);
itemId++;
});
},
),
body: Stack(
children: [
Align(
alignment: Alignment.topCenter, // you may want some changes here
child: SizedBox(
height: constraints.maxHeight,
width: constraints.maxWidth,
child: SingleChildScrollView(
child: Column(
children: [
...List.generate(
22,
(index) => Container(
height: 100,
width: double.infinity,
color: index.isEven
? Colors.deepPurple
: Colors.orangeAccent,
),
)
],
),
),
),
),
Positioned(
top: constraints.maxHeight * .2,
left: 0,
right: 0,
child: Container(
width: overlayItems.length > 0 ? constraints.maxWidth : 0,
height:
overlayItems.length > 0 ? constraints.maxHeight * .1 : 0,
color: Colors.pinkAccent,
child: Stack(
children: [
...overlayItems.toList(),
],
),
),
),
],
),
),
);
}
}
Related
In this code, when I change page (I'm using PageView as is it in code below) flutter doesn't trigger rebuild, so condition if(_page == 1) will take effect after I press "hot reload". Any tips for solution? I calling this class in main.dart (HomePage) which is Stateless widget. Could it be the problem?
Thanks for any help!
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
int _page = 0;
class Guide extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new GuideState();
}
}
class GuideState extends State<Guide> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(children: [
if (_page == 1)
Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Image(
image: AssetImage('graphics/Logo.png'),
height: MediaQuery.of(context).size.height * 0.1)),
SizedBox(height: 500, child: Page()),
]))));
}
}
class Page extends StatefulWidget {
PageState createState() => PageState();
}
class PageState extends State<Page> {
final controller = PageController(
initialPage: 0,
);
#override
Widget build(BuildContext context) {
return Scaffold(
//appBar: AppBar(title: Text('PageView Widget in Flutter')),
body: Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.95,
height: MediaQuery.of(context).size.height * 0.6,
child: PageView(
controller: controller,
onPageChanged: (page) {
setState(() {
if (page == 1) {
_page = 1;
}
});
},
pageSnapping: true,
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
//color: Colors.pink,
//child: Center(
child: Text(
'1. Tento text bude nahrán z databáze.',
style: TextStyle(fontSize: 25, color: Colors.black),
)),
Container(
//color: Colors.green,
child: Text(
'2. Tento text bude nahrán z databáze',
style: TextStyle(fontSize: 25, color: Colors.black),
)),
Container(
// color: Colors.lightBlue,
child: Text(
'3. Tento text bude nahrán z databáze',
style: TextStyle(fontSize: 25, color: Colors.black),
)),
],
),
)));
}
}
The variable _page is set as global, it has to be part of as state inorder to trigger changes, but in your case you want to change a widget base on action in another child widget, this can be done in several ways depending on your choice the easies in you case is to have a function as a parameter for your child widget Page :
class Page extends StatefulWidget {
final Function(int) onChange;
const Page({Key key, this.onChange}) : super(key: key);
PageState createState() => PageState();
}
and then call it when the page change
onPageChanged: (page) {
widget.onChange(page);
},
so with this you can handle the change in you parent widget and trigger state change
class GuideState extends State<Guide> {
int _page = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(
children:[
if (_page == 1)
Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Image(
image: AssetImage('graphics/Logo.png'),
height: MediaQuery.of(context).size.height * 0.1,
),
),
SizedBox(
height: 500,
child: Page(
onChange: (page) {
setState(() => _page = page);
},
),
),
],
),
),
),
);
}
}
int _page = 0; is not part of the state of your Guide widget. Place it here:
class GuideState extends State<Guide> {
int _page = 0;
...
I have a stack of widgets in Flutter. The lowest stack is a large image that is contained inside SingleChildScrollView. I've set up a ScrollController so I know when the image has been horizontally scrolled in the view.
Next in the stack I have several Positioned widgets (these are draggable so that they can moved around independent of each other).
What I'd like to do is when the SingleChildScrollView is scrolled, I'd like to update the position of each of the positioned widgets higher up the stack.
I've considered Stream, rebuildAllChildren and ValueNotifier but all seem quite complex for what, on the face of it, should be quite a simple thing to achieve. I'm probably missing something very obvious somewhere!
Here's my code so far:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LayoutScreen extends StatefulWidget {
LayoutScreen();
#override
_LayoutScreenState createState() => _LayoutScreenState();
}
class _LayoutScreenState extends State<LayoutScreen> {
ScrollController _controller;
Offset boxoneposition;
BuildContext context;
_scrollListener() {
print(_controller.offset);
boxoneposition=Offset(100.0, 100);
setState(() {
print(boxoneposition);
// this was a test - the value of boxoneposition is updated, however the view isn't
});
}
#override
void initState() {
_controller = ScrollController();
_controller.addListener(_scrollListener);
boxoneposition = Offset(0.0, 30);
super.initState();
}
DragBox boxOne() {
// Trying to set up outside of widget build
return DragBox(boxoneposition, 'Box One Yep', Colors.blueAccent, 1);
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _controller,
child: Container(
width: 1000,
height: 1000,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/logo.png'),
fit: BoxFit.cover,
repeat: ImageRepeat.noRepeat,
),
),
),
),
//DragBox(boxoneposition, 'Box One', Colors.blueAccent, 1),
boxOne(),
DragBox(Offset(200.0, 50.0), 'Box Two', Colors.orange, 2),
DragBox(Offset(300.0, 80.0), 'Box Three', Colors.lightGreen, 3),
],
);
}
}
class DragBox extends StatefulWidget {
final Offset initPos;
final String label;
final Color itemColor;
final int boxnumber;
DragBox(this.initPos, this.label, this.itemColor, this.boxnumber);
#override
DragBoxState createState() => DragBoxState();
}
class DragBoxState extends State<DragBox> {
Offset position = Offset(0.0, 0.0);
String imagePath="";
#override
void initState() {
super.initState();
position = widget.initPos;
}
getBoxPic() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
String key='picture'+widget.boxnumber.toString();
imagePath=prefs.getString(key);
});
print(imagePath);
return File(imagePath);
}
#override
Widget build(BuildContext context) {
return Positioned(
left: position.dx,
top: position.dy,
child: Draggable(
data: widget.itemColor,
child: Container(
width: 100.0,
height: 100.0,
color: widget.itemColor,
child: Center(
child:
Image.asset('assets/images/logo.png')
),
),
onDragStarted: () {
setState(() {
print("Foobar");
});
},
onDraggableCanceled: (velocity, offset) {
setState(() {
position = offset;
if (widget.boxnumber==1) {
print("Wibble");
}
});
},
feedback: Container(
width: 120.0,
height: 120.0,
color: widget.itemColor.withOpacity(0.5),
child: Center(
child: Text(
widget.label,
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.none,
fontSize: 18.0,
),
),
),
),
)
);
}
}
Any help greatly appreciated!
I was being a fool. Funny how walking away from something overnight and coming back to it clears the fog!
I sorted this out by simply placing an entire stack into the SingleChildScrollView. The scrollview is wider and horizontally scrollable and the rest of the elements in the stack correctly maintain their positons even if the scrollview is moved and they disappear off screen.
The solution was very simple. For completeness, here's the updated code:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LayoutScreen extends StatefulWidget {
LayoutScreen();
#override
_LayoutScreenState createState() => _LayoutScreenState();
}
class _LayoutScreenState extends State<LayoutScreen> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Arrange your images'),
backgroundColor: Colors.orange,
),
body: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Stack(
children: <Widget>[
Container(
width: 1000,
height: 1000,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/background.jpg'),
fit: BoxFit.cover,
repeat: ImageRepeat.noRepeat,
),
),
),
DragBox(Offset(100.0, 10.0), 'Box One', Colors.blueAccent, 1),
DragBox(Offset(200.0, 50.0), 'Box Two', Colors.orange, 2),
DragBox(Offset(300.0, 80.0), 'Box Three', Colors.lightGreen, 3),
]
),
)
);
}
}
class DragBox extends StatefulWidget {
final Offset initPos;
final String label;
final Color itemColor;
final int boxnumber;
DragBox(this.initPos, this.label, this.itemColor, this.boxnumber);
#override
DragBoxState createState() => DragBoxState();
}
class DragBoxState extends State<DragBox> {
Offset position = Offset(0.0, 0.0);
String imagePath="";
#override
void initState() {
super.initState();
position = widget.initPos;
}
getBoxPic() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
String key='picture'+widget.boxnumber.toString();
imagePath=prefs.getString(key);
});
print(imagePath);
return File(imagePath);
}
#override
Widget build(BuildContext context) {
return Positioned(
left: position.dx,
top: position.dy,
child: Draggable(
data: widget.itemColor,
child: Container(
width: 100.0,
height: 100.0,
color: widget.itemColor,
child: Center(
child:
Image.asset('assets/images/logo.png')
),
),
onDragStarted: () {
setState(() {
print("Foobar");
});
},
onDraggableCanceled: (velocity, offset) {
setState(() {
position = offset;
if (widget.boxnumber==1) {
print("Wibble");
}
});
},
feedback: Container(
width: 120.0,
height: 120.0,
color: widget.itemColor.withOpacity(0.5),
child: Center(
child: Text(
widget.label,
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.none,
fontSize: 18.0,
),
),
),
),
)
);
}
}
I'm trying to implement a solution where a row (containing both a TextField and a Text) in ListView.Builder is automatically for every record retrieved from a webserver.
However when I want to start typing in such a TextField the keyboard appears and immediatly disappears again.
This is the code of my screen.
class GameScreen extends StatelessWidget {
static const RouteName = "/GameScreen";
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
const horizontalMargin = 20.0;
return Scaffold(
appBar: getAppBar(),
backgroundColor: Colors.transparent,
body: Stack(
children: <Widget>[
Background(),
Column(
children: <Widget>[
Header("Starting letter: B"),
Expanded(
child: ListBlocProvider(
listWidget: GameCategoriesList(),
itemsService: CategoriesService(),
margin: EdgeInsets.only(
left: horizontalMargin,
bottom: 10,
right: horizontalMargin,
),
),
),
SizedBox(
height: 20,
),
SizedBox(
width: size.width - 40,
height: 60,
child: Container(
height: 60,
child: TextButtonWidget(
() {
// Navigator.of(context).pushNamed(GameScreen.RouteName);
},
"Stop game",
),
),
),
SizedBox(
height: 20,
)
],
),
],
),
);
}
}
This is the code of my ListBlocProvider:
class ListBlocProvider extends StatelessWidget {
final ListWidget listWidget;
final ItemsService itemsService;
final bool useColor;
final bool usePaddingTop;
final double height;
final EdgeInsets margin;
const ListBlocProvider({
#required this.listWidget,
#required this.itemsService,
this.useColor = true,
this.usePaddingTop = true,
this.height = 200,
this.margin,
});
#override
Widget build(BuildContext context) {
const horizontalMargin = 20.0;
return BlocProvider(
create: (context) => ItemsBloc(itemsService: itemsService)..add(ItemsFetched()),
child: Container(
padding: usePaddingTop ? EdgeInsets.only(top: 10) : null,
decoration: BoxDecoration(
color: this.useColor ? Color.fromRGBO(10, 50, 75, 0.9) : null,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
),
margin: this.margin,
height: this.height,
child: this.listWidget,
),
);
}
}
This is the code of my List:
class GameCategoriesList extends ListWidget {
#override
_GameCategoriesListState createState() => _GameCategoriesListState();
}
class _GameCategoriesListState extends State<GameCategoriesList> {
#override
Widget build(BuildContext context) {
return BlocBuilder<ItemsBloc, ItemsState>(
builder: (context, state) {
if (state is ItemsFailure) {
return Center(
child: Text('failed to fetch categories'),
);
}
if (state is ItemsSuccess) {
if (state.items.isEmpty) {
return Center(
child: Text('no categories found.'),
);
}
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
var textEditingController = TextEditingController();
return GameCategoryItemWidget(
key: UniqueKey(),
categoryModel: state.items[index],
textEditingController: textEditingController,
);
},
itemCount: state.items.length,
);
}
return Center(
child: LoadingIndicator(),
);
},
);
}
}
And this is the code where the both the TextField and the Text are build:
class GameCategoryItemWidget extends StatefulWidget {
final CategoryModel categoryModel;
final TextEditingController textEditingController;
const GameCategoryItemWidget({Key key, this.categoryModel, this.textEditingController}) :
super(key: key);
#override
_GameCategoryItemWidgetState createState() => _GameCategoryItemWidgetState();
}
class _GameCategoryItemWidgetState extends State<GameCategoryItemWidget> {
var formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Container(
child: Form(
key: this.formKey,
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10, top: 20, bottom: 10),
child: Text(
this.widget.categoryModel.name,
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
),
Container(
color: Colors.white,
child: InputField(
InputDecoration(labelText: this.widget.categoryModel.name),
this.widget.textEditingController,
false,
),
),
],
),
),
);
}
#override
void dispose() {
this.widget.textEditingController.dispose();
super.dispose();
}
}
The InputField is a custom widget to hide the switch between a Material and a Cupertino version of the TextField.
I've already tried to remove the Key from the custom TextField widget. The funny part is that the input is actually working, however it can't determine for which of the TextFields in the ListView the input is determined so it adds the input to all of them. I've also tried to swap things around with making Stateless widgets Statefull, but that didn't help either.
The entire build is based upon: https://bloclibrary.dev/#/flutterinfinitelisttutorial.
Hoping you guys can help me.
With the normal scroll effect, you are free to scroll how much ever you want,
but I want to have a scrollable list but only scroll full widget or 1/4 of the widget.
something like this:-
How to get a scrolling effect?
You can use PageView.
Here is the sample code. It has the paging animation. It also has attached listener to the PageController, which is useful to get current state.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _controller = PageController(viewportFraction: 0.6);
var _color = "";
#override
void initState() {
super.initState();
_controller.addListener(() {
if (_controller.page < 0.5) {
setState(() {
_color = "yellow";
});
}
if (_controller.page >= 0.5 && _controller.page < 1.5) {
setState(() {
_color = "red";
});
}
if (_controller.page >= 1.5 && _controller.page < 2) {
setState(() {
_color = "blue";
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
SizedBox(
height: 200,
),
Text(
_color,
style: TextStyle(fontSize: 40),
),
SizedBox(
height: 100,
child: PageView(
controller: _controller,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
child: Container(
color: Colors.amber,
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
width: 200,
child: Container(
color: Colors.red,
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
width: 200,
child: Container(
color: Colors.lightBlue,
),
),
),
],
),
),
],
));
}
}
I want to create a widget where you can add multiple widgets with different sizes and can change their position by using the drag and drop technique. Something like a grid view with drag and drop where you can change the position both horizontally and vertically. While you are dragging the selected widget, other widgets will move around to open up space for it.
Does anyone have any suggestion where to start or are there already some examples that are implementing what I am looking for?
You can also try this easier one (It doesn't include Feedback)
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: Scaffold(body: HomePage()));
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Offset offset = Offset.zero;
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Positioned(
left: offset.dx,
top: offset.dy,
child: GestureDetector(
onPanUpdate: (details) {
setState(() {
offset = Offset(offset.dx + details.delta.dx, offset.dy + details.delta.dy);
});
},
child: Container(width: 100, height: 100, color: Colors.blue),
),
),
],
);
}
}
Although this may not answer your question but people who are looking for simple drag and drop widget, then here is the example.
See my 2nd answer for more simpler way
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Drag app"),
),
body: HomePage(),
),
);
}
}
class HomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _HomePageState();
}
}
class _HomePageState extends State<HomePage> {
double width = 100.0, height = 100.0;
Offset position ;
#override
void initState() {
super.initState();
position = Offset(0.0, height - 20);
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Positioned(
left: position.dx,
top: position.dy - height + 20,
child: Draggable(
child: Container(
width: width,
height: height,
color: Colors.blue,
child: Center(child: Text("Drag", style: Theme.of(context).textTheme.headline,),),
),
feedback: Container(
child: Center(
child: Text("Drag", style: Theme.of(context).textTheme.headline,),),
color: Colors.blue[300],
width: width,
height: height,
),
onDraggableCanceled: (Velocity velocity, Offset offset){
setState(() => position = offset);
},
),
),
],
);
}
}
I've created a package called reorderables that solved this problem. You just need to tell the package your function to be called when drag and drop is done onReorder(int oldIndex, int newIndex).
This example has 9 icon widgets in a grid -
Screenshot: ReorderableWrap
class _WrapExampleState extends State<WrapExample> {
final double _iconSize = 90;
List<Widget> _tiles;
#override
void initState() {
super.initState();
_tiles = <Widget>[
Icon(Icons.filter_1, key: ValueKey(1), size: _iconSize),
Icon(Icons.filter_2, key: ValueKey(2), size: _iconSize),
Icon(Icons.filter_3, key: ValueKey(3), size: _iconSize),
Icon(Icons.filter_4, key: ValueKey(4), size: _iconSize),
Icon(Icons.filter_5, key: ValueKey(5), size: _iconSize),
Icon(Icons.filter_6, key: ValueKey(6), size: _iconSize),
Icon(Icons.filter_7, key: ValueKey(7), size: _iconSize),
Icon(Icons.filter_8, key: ValueKey(8), size: _iconSize),
Icon(Icons.filter_9, key: ValueKey(9), size: _iconSize),
];
}
#override
Widget build(BuildContext context) {
void _onReorder(int oldIndex, int newIndex) {
setState(() {
Widget row = _tiles.removeAt(oldIndex);
_tiles.insert(newIndex, row);
});
}
return ReorderableWrap(
spacing: 8.0,
runSpacing: 4.0,
padding: const EdgeInsets.all(8),
children: _tiles,
onReorder: _onReorder
);
}
}
If you want to limit the number of columns, you can use an optional parameter named maxMainAxisCount
Here is example of draggable text
class DraggableText extends StatefulWidget {
final Offset initialOffset;
final String text;
DraggableText(this.text, this.initialOffset);
#override
_DraggableTextState createState() => new _DraggableTextState();
}
class _DraggableTextState extends State<DraggableText> {
Offset position = new Offset(0.0, 0.0);
#override
void initState() {
super.initState();
position = widget.initialOffset;
}
#override
Widget build(BuildContext context) {
final item = new LabelBox(size: new Size.square(100.0), label: widget.text);
final avatar = new LabelBox(
size: new Size.square(150.0), label: widget.text, opacity: 0.4);
final draggable = new Draggable(
data: widget.text,
feedback: avatar,
child: item,
childWhenDragging: new Opacity(opacity: 0.0, child: item),
onDraggableCanceled: (velocity, offset) {
print('_DragBoxState.build -> offset ${offset}');
setState(() => position = offset);
});
return new Positioned(
left: position.dx, top: position.dy, child: draggable);
}
}
You can check full example and a more advanced one here https://github.com/rxlabz/flutter_dropcity
I cannot write comments becaus of my reputation but I wanted to answer to this question from the comments of CopsOnRoad's answer:
I don't want show feedback view instead of that I want to drag
original view. Is it possible?
If someones looking for this too, you could use: childWhenDragging: Container().
You're still dragging the feedback but the original child will be hidden.
...
child: Draggable(
child: Container(
width: width,
height: height,
color: Colors.blue,
child: Center(child: Text("Drag", style: Theme.of(context).textTheme.headline,),),
),
feedback: Container(
child: Center(
child: Text("Drag", style: Theme.of(context).textTheme.headline,),),
color: Colors.blue[300],
width: width,
height: height,
),
childWhenDragging: Container(), // <-- so it looks like the original view is beeing dragged
onDraggableCanceled: (Velocity velocity, Offset offset){
setState(() => position = offset);
},
),
...
You can also make use of LongPressDraggable, for this you need to long press your widget and then only you can drag it.
Offset _offset = Offset.zero;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: LayoutBuilder(
builder: (context, constraints) {
return Stack(
children: [
Positioned(
left: _offset.dx,
top: _offset.dy,
child: LongPressDraggable(
feedback: FlutterLogo(colors: Colors.orange, size: 100),
child: FlutterLogo(colors: Colors.green, size: 100),
onDragEnd: (details) {
setState(() {
final adjustment = MediaQuery.of(context).size.height - constraints.maxHeight;
_offset = Offset(details.offset.dx, details.offset.dy - adjustment);
});
},
),
),
],
);
},
),
);
}