How to switching the stack's widget of index - flutter

How to switching the stack's widget smoothly when clicking the smaller widget, mentioned as the image below
When user has clicked Widget B, Widget B will zoom out, and Widget A will zoom in, and the stack position should be changed when clicked the smaller widget.
Any code sample for reference would be appreciated, thanks!

try this:
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> {
Widget _a = Container(
color: Colors.red, width: double.infinity, height: double.infinity);
Widget _b = Container(
color: Colors.green, width: double.infinity, height: double.infinity);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
width: 400,
height: 200,
child: Stack(
children: <Widget>[
Container(
width: 400,
height: 200,
child: _a,
),
Positioned(
bottom: 20,
left: 20,
child: GestureDetector(
onTap: (){
Widget _swap = _b;
_b = _a;
_a = _swap;
setState((){});
},
child: Container(
width: 80,
height: 40,
child: _b,
),
),
),
],
),
),
);
}
}

Related

Why does my code not increase the size of the container?

I am trying to increase the size of the container using GestureDetector's onTap method. But when i tap on the container, nothing happens.
I can't figure out what's wrong? Would you suggest me any other way or any package which can produce the same result.
class DemoPage extends StatefulWidget {
#override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
CustomContainer container = CustomContainer();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onTap: () {
setState(() {
container.expandContainer();
});
},
child: container,
)),
);
}
}
class CustomContainer extends StatelessWidget {
Container _container = Container(
color: Colors.yellow,
width: 200.0,
height: 100.0,
);
void expandContainer() {
//Assignment Operator used with Ternary operator
_container = _container ==
Container(
color: Colors.yellow,
width: 200.0,
height: 300.0,
)
? Container(
color: Colors.yellow,
width: 200.0,
height: 100.0,
)
: Container(
color: Colors.yellow,
width: 200.0,
height: 300.0,
);
}
#override
Widget build(BuildContext context) {
return _container;
}
}
I prefer using AnimatedContainer for cases like this.
class DemoPage extends StatefulWidget {
const DemoPage({Key? key}) : super(key: key);
#override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
bool isExanded = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onTap: () {
setState(() {
isExanded = !isExanded;
});
print("tapped");
},
child: AnimatedContainer(
color: Colors.yellow,
width: 200.0,
height: isExanded ? 300 : 100.0,
duration: const Duration(seconds: 2),
),
)),
);
}
}

Can you programmatically put a Draggable inside a DragTarget?

This sounds a strange thing to ask! But I have two drag targets, and two draggables. I want them to start off one in each target. Then, when one is drag&dropped onto the second target, the second target's draggable needs to jump across to the first target.
I guess the problem resolves down to whether you can programmatically put a draggable inside a target. Does this look possible, or is a DragTarget not suitable?
Some example code - I can't start the draggables inside the dragtargets
import 'package:flutter/material.dart';
MyDraggable drag1 = new MyDraggable(Colors.red);
MyDraggable drag2 = new MyDraggable(Colors.green);
MyDragTarget target1 = new MyDragTarget();
MyDragTarget target2 = new MyDragTarget();
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(fontFamily: 'PressStart'),
home: MyHomeScreen(),
);
}
}
class MyHomeScreen extends StatefulWidget {
MyHomeScreen({Key key}) : super(key: key);
createState() => MyHomeScreenState();
}
class MyHomeScreenState extends State<MyHomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.red[100],
appBar: AppBar(
toolbarHeight: 70.0,
title: Center(child: Text('Swap the draggables')),
backgroundColor: Colors.pink,
),
body: Container(
color: Colors.yellow[200],
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [target1, drag1, drag2, target2],
// children: [target1, SizedBox(width: 100), target2],
),
),
Text('Q1: Can the Draggables be started in the DragTargets?'),
Text('Q2: If you drag from one target to the other, '
'can the second swap to the other target?'),
],
),
),
);
} // End build()
} // End class MyHomeScreenState
class MyDragTarget extends StatelessWidget {
bool dragAccepted = false;
Color acceptedColor;
#override
Widget build(BuildContext context) {
return Stack(children: [
Container(color: Colors.blue,height: 90.0,width: 90.0,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: DragTarget<Color>(
builder: (context, List<Color> acceptedData, rejectedData) {
if (dragAccepted) {
return MyDraggable(acceptedColor);
} else {
return Container(color: Colors.grey,height: 50,width: 50,);
}
},
onWillAccept: (aColor) {
acceptedColor = aColor;
return true;
},
onMove: (moveData) {},
onAccept: (aColor) { dragAccepted = true; },
onLeave: (data) {},
),
),
),
]);
} // Build
} // End Class MyDragTarget
class MyDraggable extends StatefulWidget {
MyDraggable(this.color);
final Color color;
#override
_MyDraggableState createState() => _MyDraggableState();
}
class _MyDraggableState extends State<MyDraggable> {
#override
Widget build(BuildContext context) {
return Draggable(
data: widget.color,
child: Container(color: widget.color, height: 50, width: 50),
feedback: Container(color: widget.color, height: 50, width: 50),
childWhenDragging:
Container(color: Colors.pink[100], height: 50, width: 50),
onDragStarted: () {},
onDragEnd: (dragDetails) {
setState(() {});
},
onDragCompleted: () {},
onDraggableCanceled: (velocity, offset) {},
);
}
}
For the default Draggable from Flutter SDK, there is no method provided that allowed us to modify the offset/ position of the Draggable displaying on the UI (all those infos are stored in DraggableDetails of a Draggable).
With that said, there are 2 options you can try out:
Create a custom Draggable class that allows for manipulating its position on UI programatically
Change the property of the children of Draggable widget based on the onWillAccept callback of the DragTarget class (the color of each Container in this case)

Change image onTap

I was trying to change the image every time onTap.
But somehow the image is only getting changed only once.
Please review this piece of code and mention where am I going wrong
import 'package:flutter/material.dart';
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
String imagePath = "images/img4.jpg";
class _DemoState extends State<Demo> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: Container(
width: 100,
height: 100,
child: GestureDetector(
onTap: () {
setState(() {
imagePath = "images/tmhm.jpg";
});
},
child: CircleAvatar(
maxRadius: 20.0,
child: Image.asset(imagePath),
),
),
),
),
),
);
}
}
Place your imagePath in your State class(_DemoState)
import 'package:flutter/material.dart';
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo> {
String imagePath = "images/img4.jpg";
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: Container(
width: 100,
height: 100,
child: GestureDetector(
onTap: () {
if(imagePath == "images/img4.jpg"){
imagePath = "images/tmhm.jpg";
}else{
imagePath = "images/img4.jpg";
}
setState(() {});
},
child: CircleAvatar(
maxRadius: 20.0,
child: Image.asset(imagePath),
),
),
),
),
),
);
}
}

Multiply gesture detector in flutter

I have two views one over another and want get touches in both views. But now get touches only second view.
How can I configure GestureDetector that all touches will be send both widgets
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
TestPage();
#override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
backgroundColor: Colors.blueAccent,
body: Stack(
children: [_renderFirstWidget(), _renderSecondWidget()],
),
);
}
Widget _renderFirstWidget() {
return Center(
child: GestureDetector(
onTap: () {
print('first');
},
child: Container(height: 150, width: 150, color: Colors.greenAccent)),
);
}
Widget _renderSecondWidget() {
return Center(
child: GestureDetector(
onTap: () {
print('second');
},
child: Container(
height: 350,
width: 350,
color: Colors.redAccent.withOpacity(0.3))));
}
}

How to move a widget in the screen in Flutter

I am using flutter and i have a container with the shape of a circle using this code
new Container(
width: 50.0,
height: 50.0,
decoration: new BoxDecoration(
shape: BoxShape.circle)
I want to make this circle move on the screen like this
how can I do this?
Here it is:
import 'package:flutter/material.dart';
class SecondScreen 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.red[800],
width: width,
height: height,
),
onDraggableCanceled: (Velocity velocity, Offset offset){
setState(() => position = offset);
},
),
),
],
);
}
}
What you are looking for is Draggable widget. You can then handle the translation using onDraggableCanceled which is passed and offset that you can be used to update the placement
onDraggableCanceled :(velocity,offset){
//update the position here
}
Update
After checking the image you will need "Drop me here" part to be a DragTarget that has a method onAccept which will handles the logic when you drag and drop your Draggable
First, wrap your Container inside the Stack with Positioned.
Then, use Pan Gesture to implement a Pan in your Container and use onPan... methods to handle Pan Gesture
Here is code:
Offset position;
#override
void initState() {
super.initState();
position = Offset(10, 10);
}
#override
Widget build(BuildContext context) {
double _width = MediaQuery.of(context).size.width;
double _height = _width * 9 / 16;
return GestureDetector(
onPanStart: (details) => _onPanStart(context, details),
onPanUpdate: (details) => _onPanUpdate(context, details, position),
onPanEnd: (details) => _onPanEnd(context, details),
onPanCancel: () => _onPanCancel(context),
child: SafeArea(
child: Stack(
children: <Widget>[
Positioned(
top: position.dy,
child: Container(
color: Colors.red,
width: _width,
height: _height,
),
),
],
),
),
);
}
void _onPanStart(BuildContext context, DragStartDetails details) {
print(details.globalPosition.dy);
}
void _onPanUpdate(BuildContext context, DragUpdateDetails details, Offset offset) {
setState(() {
position = details.globalPosition;
});
}
void _onPanEnd(BuildContext context, DragEndDetails details) {
print(details.velocity);
}
void _onPanCancel(BuildContext context) {
print("Pan canceled !!");
}
Hope this helps!
You can use Draggable class for dragging the item which you want to drag and for placing it or sticking it to somewhere on the screen you have to wrap that item with DragTarget class. In DragTarget class onAccept method is there where you can write the logic. You can also take a reference to my code here it is
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.indigo,
),
home: new MyHomePage(title: 'Flutter Demo Drag Box'),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(title),
),
body:
new DragGame(), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class DragGame extends StatefulWidget {
#override
_DragGameState createState() => new _DragGameState();
}
class _DragGameState extends State<DragGame> {
int boxNumberIsDragged;
#override
void initState() {
boxNumberIsDragged = null;
super.initState();
}
#override
Widget build(BuildContext context) {
return new Container(
constraints: BoxConstraints.expand(),
color: Colors.grey,
child: new Stack(
children: <Widget>[
buildDraggableBox(1, Colors.red, new Offset(30.0, 100.0)),
buildDraggableBox(2, Colors.yellow, new Offset(30.0, 200.0)),
buildDraggableBox(3, Colors.green, new Offset(30.0, 300.0)),
],
));
}
Widget buildDraggableBox(int boxNumber, Color color, Offset offset) {
return new Draggable(
maxSimultaneousDrags: boxNumberIsDragged == null || boxNumber == boxNumberIsDragged ? 1 : 0,
child: _buildBox(color, offset),
feedback: _buildBox(color, offset),
childWhenDragging: _buildBox(color, offset, onlyBorder: true),
onDragStarted: () {
setState((){
boxNumberIsDragged = boxNumber;
});
},
onDragCompleted: () {
setState((){
boxNumberIsDragged = null;
});
},
onDraggableCanceled: (_,__) {
setState((){
boxNumberIsDragged = null;
});
},
);
}
Widget _buildBox(Color color, Offset offset, {bool onlyBorder: false}) {
return new Container(
height: 50.0,
width: 50.0,
margin: EdgeInsets.only(left: offset.dx, top: offset.dy),
decoration: BoxDecoration(
color: !onlyBorder ? color : Colors.grey,
border: Border.all(color: color)),
);
}
}