I wanted to ask how I can automatically resize the two containers here when it is dragged (see picture). It should work so that I can drag in the middle (where the two meet), and the one then becomes larger or smaller.
I can't find anything helpful on the internet :c
At the moment, both containers are in a row.
My code:
Row(children: [
Container(
color: Colors.red,
width: MediaQuery.of(context).size.width * .5,
height: double.infinity),
Container(
color: Colors.blue,
width: MediaQuery.of(context).size.width * .5,
height: double.infinity)
])
Can someone here maybe help me?
Try this widget
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
double? leftPart;
#override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
leftPart ??= constraints.maxWidth / 2; // if you need initially half
return GestureDetector(
onPanUpdate: (details) {
double tapPos = details.globalPosition.dx;
const double softPX = 20; //user flexibility
if (tapPos - 20 < leftPart! && tapPos + 20 > leftPart!) {
leftPart = details.globalPosition.dx;
setState(() {});
}
},
child: Row(
children: [
Expanded(
child: Container(
color: Colors.red,
width: leftPart,
height: double.infinity),
),
Container(
color: Colors.blue,
width: constraints.maxWidth - (leftPart ?? 0.0),
height: double.infinity)
],
),
);
}),
);
}
}
If you like to handle overflow on drag, use
color: Colors.blue,
width: constraints.maxWidth - (leftPart ?? 0.0) >
constraints.maxWidth
? constraints.maxWidth
: constraints.maxWidth - (leftPart ?? 0.0) < 0
? 0
: constraints.maxWidth - (leftPart ?? 0.0),
Related
I have the code below, which I shortened as much as possible to make it easier to deal with. I want to scroll down to show the default appBar, not the background. I did some solutions, but it didn't work. Switch between them with a smooth motion.
I want to use the same existing code because I built on it.
I have attached an illustration of the problem
The main code:
import 'package:flutter/material.dart';
import 'home_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
HomePage code:
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
const SliverPersistentHeader(pinned: true, delegate: SliverHeaderDelegateComponent(expandedHeight: 300)),
SliverList(
delegate: SliverChildListDelegate(
[
Container(
height: 1000,
color: Colors.blue.withOpacity(0.5),
child: const Center(child: Text('Body')),
)
],
),
),
],
),
);
}
}
The SliverHeaderDelegateComponent code :
class SliverHeaderDelegateComponent extends SliverPersistentHeaderDelegate {
final double expandedHeight;
const SliverHeaderDelegateComponent({required this.expandedHeight});
#override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
final appBarSize = expandedHeight - shrinkOffset;
final proportion = 2 - (expandedHeight / appBarSize);
final percent = proportion < 0 || proportion > 1 ? 0.0 : proportion;
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) => SizedBox(
height: expandedHeight + expandedHeight / 2,
child: Stack(
clipBehavior: Clip.none,
children: [
Container(
height: 500,
decoration: const BoxDecoration(
color: Colors.black,
image: DecorationImage(
image: NetworkImage(
'https://www.digitalartsonline.co.uk/cmsdata/slideshow/3662115/baby-driver-rory-hi-res.jpg'),
fit: BoxFit.cover,
),
),
),
PositionedDirectional(
start: 0.0,
end: 0.0,
top: appBarSize > 0 ? appBarSize : 0,
bottom: -100,
child: Opacity(
opacity: percent,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 30 * percent),
child: const Card(
elevation: 20.0,
child: Center(
child: Text("Widget"),
),
),
),
),
),
],
),
),
);
}
#override
double get maxExtent => expandedHeight + expandedHeight / 2;
#override
double get minExtent => kToolbarHeight;
#override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}
Here is the solution using SliverHeaderDelegateComponent as you requested.
In this example, the AppBar is shown when collapsed, but you can uncomment the commented part if you want to show it on expand. (UPDATE: improved fading as requested in the comment section)
class SliverHeaderDelegateComponent extends SliverPersistentHeaderDelegate {
final double expandedHeight;
const SliverHeaderDelegateComponent({required this.expandedHeight});
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
final deadline = (expandedHeight + minExtent);
double percent = shrinkOffset > deadline ? 1 : shrinkOffset / deadline;
final appBarSize = expandedHeight - shrinkOffset;
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) => SizedBox(
height: expandedHeight + expandedHeight / 2,
child: Stack(
clipBehavior: Clip.none,
children: [
// shrinkOffset == 0 // if you want to show it on expand
shrinkOffset > expandedHeight + minExtent // show it on collapse
? AppBar(title: Text('App Bar'))
: Container(
height: 500,
decoration: const BoxDecoration(
color: Colors.black,
image: DecorationImage(
image: NetworkImage(
'https://www.digitalartsonline.co.uk/cmsdata/slideshow/3662115/baby-driver-rory-hi-res.jpg'),
fit: BoxFit.cover,
),
),
),
PositionedDirectional(
start: 0.0,
end: 0.0,
top: appBarSize > 0 ? appBarSize : 0,
bottom: -100,
child: Opacity(
opacity: 1 - percent,
// opacity: percent < 0.5 ? 1 : (1 - percent) * 2, // if you want to start fading when reach half way scroll
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 30 * percent),
child: const Card(
elevation: 20.0,
child: Center(
child: Text("Widget"),
),
),
),
),
),
],
),
),
);
}
#override
double get maxExtent => expandedHeight + expandedHeight / 2;
#override
double get minExtent => kToolbarHeight;
#override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}
Im trying to create a card or Container with borderRadius to change its top side shape like a plane Knob but i cannot make it im attaching a picture so please if any one know how to create this in flutter help me thanks
Shape:
You can play with CliPPath, change the control point value to make it perfect.
class Test extends StatefulWidget {
const Test({super.key});
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green,
body: LayoutBuilder(
builder: (p0, constaints) {
final width = constaints.maxWidth;
final double viewWidth = width * .8;
return Center(
child: SingleChildScrollView(
child: SizedBox(
width: viewWidth,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//top Curve
ClipPath(
clipper: CurvePath(),
child: Container(
width: viewWidth,
height: viewWidth,
color: Colors.white,
),
),
Container(
width: viewWidth,
height: 1200,
color: Colors.white,
)
],
),
),
),
);
},
),
);
}
}
class CurvePath extends CustomClipper<Path> {
#override
Path getClip(Size size) {
return Path()
..moveTo(0, size.height)
..quadraticBezierTo(20, 0, size.width / 2, 0)
..quadraticBezierTo(size.width, 0, size.width, size.height)
..lineTo(0, size.height);
}
#override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
return false;
}
}
Also shapeBorder may help.
I have a Positioned widget that is draggable, by using Offset and wrapping it inside a Gesture Detector to update its position, and I want to constrain the area that this widget can move, so it cannot go beyond the boundaries. The structure is like this:
Scaffold -> Stack -> Positioned(Circle)
As it is shown below, I want the circle to move only in the are inside the gray lines. Is it possible?
Provide 2x value as limit, I did for touch position purpose.
also, both dx and dy axis can work separately. If you don't want it, you can combine two condition on a single setState.
Result
Widget
class HomeWidget extends StatefulWidget {
#override
_HomeWidgetState createState() => _HomeWidgetState();
}
class _HomeWidgetState extends State<HomeWidget> {
double dx = 0;
double dy = 0;
get limit => 50;
get containerSize => 50;
#override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => Stack(
children: [
Positioned(
left: limit * .5,
child: Container(
height: constraints.maxHeight,
width: 5,
color: Colors.grey,
),
),
Positioned(
bottom: limit * .5,
child: Container(
width: constraints.maxWidth,
height: 5,
color: Colors.grey,
),
),
Positioned(
top: dy - containerSize * .5,
left: dx - containerSize * .5,
child: Container(
height: containerSize,
width: containerSize,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.deepPurple,
),
),
),
GestureDetector(
onPanUpdate: (details) {
if (details.localPosition.dx > limit)
setState(() {
dx = details.localPosition.dx;
});
if (details.localPosition.dy < constraints.maxHeight - limit)
setState(() {
dy = details.localPosition.dy;
});
print(" $dx, $dy ");
},
),
],
),
),
);
}
}
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(),
],
),
),
),
],
),
),
);
}
}
My end goal is to achieve somethinng like this:
As you can see there's the drag handle is required to rotate this image.
I have a following code:
import 'package:flutter/material.dart';
double ballRadius = 7.5;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
double _angle = 0.0;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: SafeArea(
child: Stack(
children: [
Positioned(
top: 100,
left: 100,
child: Transform.rotate(
angle: _angle,
child: Column(
children: [
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(30),
),
child: LayoutBuilder(
builder: (context, constraints) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onPanUpdate: (DragUpdateDetails details) {
Offset centerOfGestureDetector = Offset(
constraints.maxWidth / 2,
constraints.maxHeight / 2,
);
final touchPositionFromCenter =
details.localPosition -
centerOfGestureDetector;
print(touchPositionFromCenter.direction);
setState(() {
_angle = touchPositionFromCenter.direction;
});
},
);
},
),
),
Container(
height: 30,
width: 5,
color: Colors.black,
),
Container(
height: 200,
width: 200,
color: Colors.red,
),
],
),
),
)
],
),
),
),
);
}
}
It is working. But sometimes it's too fast or too slow. Please help me fix this issue.
I made a few modifications to the code, notably
Treating the "real" centerOfGestureDetector as the center of all the items you would like to rotate
Determining and tracking the change in angle with the onPanStart,onPanEnd and onPanUpdate methods
import 'package:flutter/material.dart';
double ballRadius = 7.5;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
double _angle = 0.0;
double _oldAngle = 0.0;
double _angleDelta = 0.0;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: SafeArea(
child: Stack(
children: [
Positioned(
top: 100,
left: 100,
child: Transform.rotate(
angle: _angle,
child: Column(
children: [
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(30),
),
child: LayoutBuilder(
builder: (context, constraints) {
// Offset centerOfGestureDetector = Offset(
// constraints.maxWidth / 2, constraints.maxHeight / 2);
/**
* using center of positioned element instead to better fit the
* mental map of the user rotating object.
* (height = container height (30) + container height (30) + container height (200)) / 2
*/
Offset centerOfGestureDetector =
Offset(constraints.maxWidth / 2, 130);
return GestureDetector(
behavior: HitTestBehavior.translucent,
onPanStart: (details) {
final touchPositionFromCenter =
details.localPosition -
centerOfGestureDetector;
_angleDelta = _oldAngle -
touchPositionFromCenter.direction;
},
onPanEnd: (details) {
setState(
() {
_oldAngle = _angle;
},
);
},
onPanUpdate: (details) {
final touchPositionFromCenter =
details.localPosition -
centerOfGestureDetector;
setState(
() {
_angle = touchPositionFromCenter.direction +
_angleDelta;
},
);
},
);
},
),
),
Container(
height: 30,
width: 5,
color: Colors.black,
),
Container(
height: 200,
width: 200,
color: Colors.red,
),
],
),
),
)
],
),
),
),
);
}
}