My Flutter application makes use of the relatively new Windows build tools and the community fluent_ui package.
In an attempt to make my application look more native, I have opted to remove the default Windows title bar using the window_manager package and implement my own. However, this introduces the issue of not being able to move the window by dragging the top of it.
Is there a way to make a widget a window drag point to allow for this?
I recently found a solution by making DraggableAppBar. I'm also using window_manager package to add window control buttons to appbar.
Solution: use DraggableAppBar instead of AppBar in scaffold.
import 'package:flutter/material.dart';
import 'package:universal_platform/universal_platform.dart';
import 'package:window_manager/window_manager.dart';
class DraggebleAppBar extends StatelessWidget implements PreferredSizeWidget {
final String title;
final Brightness brightness;
final Color backgroundColor;
const DraggebleAppBar({
super.key,
required this.title,
required this.brightness,
required this.backgroundColor,
});
#override
Widget build(BuildContext context) {
return Stack(
children: [
getAppBarTitle(title),
Align(
alignment: AlignmentDirectional.centerEnd,
child: SizedBox(
height: kToolbarHeight,
width: 200,
child: WindowCaption(
backgroundColor: backgroundColor,
brightness: brightness,
),
),
)
],
);
}
Widget getAppBarTitle(String title) {
if (UniversalPlatform.isWeb) {
return Align(
alignment: AlignmentDirectional.center,
child: Text(title),
);
} else {
return DragToMoveArea(
child: SizedBox(
height: kToolbarHeight,
child: Align(
alignment: AlignmentDirectional.center,
child: Text(title),
),
),
);
}
}
#override
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}
Related
I am having an issue when trying to blur a container in a Row widget when the user hovers over it (on Chrome). I have a custom widget called PanelLink, which is supposed to shrink in size and blur the background when the cursor goes over it. It works, but for some reason when hovering over one it also blurs every widget to the left not just itself.
FrontPage.dart:
import 'package:flutter/material.dart';
import 'package:website_v2/CustomWidgets/PanelLink.dart';
class FrontPage extends StatefulWidget {
FrontPage();
#override
_FrontPageState createState() => _FrontPageState();
}
class _FrontPageState extends State<FrontPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Website'),
centerTitle: false,
backgroundColor: Colors.blue[900],
),
backgroundColor: Colors.blueGrey[900],
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PanelLink(false, 'assets/education.jpg'),
PanelLink(true, 'assets/about.jpeg'),
PanelLink(false, 'assets/projects2.jpg'),
],
),
),
);
}
}
PanelLink.dart:
import 'package:flutter/material.dart';
import 'dart:ui';
class PanelLink extends StatefulWidget {
PanelLink(this._blur, this.imageLoc);
final bool _blur;
final String imageLoc;
#override
PanelLinkState createState() => PanelLinkState(_blur, imageLoc);
}
class PanelLinkState extends State<PanelLink> {
PanelLinkState(this._blur, this.imageLoc);
bool isHovering = false;
bool _blur;
String imageLoc;
Widget build(BuildContext context) {
return Expanded(
child: InkWell(
onTap: () => null,
onHover: (hovering) {
setState(() => {isHovering = hovering});
},
child: Stack(children: [
AnimatedContainer(
duration: const Duration(milliseconds: 1000),
curve: Curves.ease,
margin: EdgeInsets.all(isHovering ? 20 : 0),
decoration: BoxDecoration(
color: Colors.black,
image: DecorationImage(
image: AssetImage(imageLoc), fit: BoxFit.cover)),
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: isHovering ? 5 : 0, sigmaY: isHovering ? 5 : 0),
child: Container(
color: Colors.black.withOpacity(0.1),
)),
),
Text('Test')
]),
));
}
}
Here is a picture of the issue occurring. I am hovering the mouse over panel 2, but both panel 1 and 2 are blurred but not panel 3. If I hover over panel 1 only panel 1 is blurred. If I hover over panel 3, all of them are blurred.
I experimented by only making panel two have the BackdropFilter Widget, but panel 1 still got blurred when hovering over panel 2.
Since your using AnimatedContainer widget the problem might be it cant identify the difference between his child widget. Try adding a key value identifier
AnimatedContainer(
child: Container(
key: ValueKey("imageA"), //make sure that this is different on every widget, its better to passed some value here thats different on the other refactored widget
Try experimenting it might work for you
),
),
I am learning flutter for some time. But I do not seem to understand fully what is FractionalTranslation class despite docs and some examples.
Documentation says: FractionalTranslation class applies a translation transformation before painting its child.
But what does it mean? Could you explain it to me in more detail?
FractionalTranslation class is essentially a type of Transform, and it is also used to do The difference of translation transformation is that its translation unit is a multiple of the width and height of the control. It is defined as follows
FractionalTranslation({
Key key,
#required Offset translation,
bool transformHitTests: true,
Widget child })
It can be seen that its definition is the Transform.translatesame. The difference is translation the understanding of parameters. Let’s use a few examples to explain the use of FractionalTranslation
FractionalTranslation use
The translation distance of the Text control to the right is 0.5 times the width of the Text control
Container(
color: Colors.amberAccent,
alignment: Alignment.center,
child: FractionalTranslation(
translation: Offset(0.5, 0),
child: Text("Hello world")),
),
The distance to translate the Text control to the right is 2 times the width of the Text control
Container(
color: Colors.amberAccent,
alignment: Alignment.center,
child: FractionalTranslation(
translation: Offset(2, 0),
child: Text("Hello world")),
),
Move the Text control to the right and down. The right translation distance is 1 times the Text width, and the downward translation distance is 1.5 times the Text height.
Container(
color: Colors.amberAccent,
alignment: Alignment.center,
child: FractionalTranslation(
translation: Offset(1, 1.5),
child: Text("Hello world")),
),
Complete example
import 'package:flutter/material.dart';
import 'dart:math' as math;
class TransformDemo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primaryColor: Colors.blue),
home: HomeWidget(),
);
}
}
class HomeWidget extends StatefulWidget {
#override
State createState() {
return HomeState();
}
}
class HomeState extends State<HomeWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("TransformDemo"),),
body: Container(
color: Colors.amberAccent,
alignment: Alignment.center,
child: FractionalTranslation(
translation: Offset(1, 0),
child: Text("Hello world")),
),
);
}
}
I'm using Transforms in Flutter to create a scrolling carousel for selecting from various options.
This uses standard elements such as ListView.builder, which all works fine, aside from the fact that the parent widget of the Transform doesn't scale down to fit the content as seen here:
Here's the code used to generate the 'card' (there was actually a Card in there, but I've stripped it out in an attempt to get everything to scale correctly):
return Align(
child: Transform(
alignment: Alignment.center,
transform: mat,
child: Container(
height: 220,
color: color,
width: MediaQuery.of(context).size.width * 0.7,
child: Text(
offset.toString(),
style: TextStyle(color: Colors.white, fontSize: 12.0),
),
),
),
);
}
Even if I remove the 'height' parameter of the Container (so everything scales to fit the 'Text' widget), the boxes containing the Transform widgets still have the gaps around them.
Flutter doesn't seem to have any documentation to show how to re-scale the parent if the object within is transformed - anyone here knows or has any idea of a workaround?
EDIT: The widget returned from this is used within a build widget in a Stateful widget. The stack is Column > Container > ListView.builder.
If I remove the Transform, the Containers fit together as I'd like - it seems that performing a perspective transform on the Container 'shrinks' it's content (in this case, the color - check the linked screen grab), but doesn't re-scale the Container itself, which is what I'm trying to achieve.
I have a tricky solution for this: addPostFrameCallback + overlay.
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
// ignore: must_be_immutable
class ChildSizeWidget extends HookWidget {
final Widget Function(BuildContext context, Widget child, Size size) builder;
final Widget child;
final GlobalKey _key = GlobalKey();
OverlayEntry _overlay;
ChildSizeWidget({ this.child, this.builder });
#override
Widget build(BuildContext context) {
final size = useState<Size>(null);
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timestamp) {
_overlay = OverlayEntry(
builder: (context) => Opacity(
child: SingleChildScrollView(
child: Container(
child: child,
key: _key,
),
),
opacity: 0.0,
),
);
Overlay.of(context).insert(_overlay);
WidgetsBinding.instance.addPostFrameCallback((timestamp) {
size.value = _key.currentContext.size;
_overlay.remove();
});
});
return () => null;
}, [child]);
if (size == null || size.value == null) {
return child;
} else {
return builder(context, child, size.value);
}
}
}
Usage:
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
class HomeView extends HookWidget {
#override
Widget build(BuildContext context) {
final change = useState<bool>(false);
final normal = Container(
color: Colors.blueAccent,
height: 200.0,
width: 200.0,
);
final big = Container(
color: Colors.redAccent,
height: 300.0,
width: 200.0,
);
return Column(
children: [
Container(
alignment: Alignment.center,
child: ChildSizeWidget(
child: change.value ? big : normal,
builder: (context, child, size) => AnimatedContainer(
alignment: Alignment.center,
child: SingleChildScrollView(child: child),
duration: Duration(milliseconds: 250),
height: size.height,
),
),
color: Colors.grey,
),
FlatButton(
child: Text('Toggle child'),
onPressed: () => change.value = !change.value,
color: Colors.green,
),
],
);
}
}
I have a menu with several options, they have different height and with the help of the animations this is ok, it's working really nice for me.
Why are you using Align, as much as I can see in your code, there is no property set or used, to align anything. So try removing Align widget around Transform.
Because according to the documentation, Transform is such a widget that tries to be the same size as their children. So that would satisfy your requirement.
For more info check out this documentation: https://flutter.dev/docs/development/ui/layout/box-constraints
I hope it helps!
I try to create a reusable widget but some error happens...
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class CustomLogo extends StatelessWidget {
#override
Widget showLogo(var nameImage, double radiusImage, double LeftPadding) {
return new Hero(
tag: 'hero',
child: Padding(
padding: EdgeInsets.fromLTRB(LeftPadding, 70.0, 0.0, 0.0),
child: CircleAvatar(
backgroundColor: Colors.transparent,
radius: radiusImage,
child: Image.asset('assets/' + name),
),
),
);
}
}
And I don't understand override and the "construction" of the widget, how I can use var in the widget
You have to create a constructor to get values from where you are trying to call.
In following way you can create separate widget and pass arguments.
Moreover, here one mistake is left and it is hero tag. you are setting constant hero tag, which is fine if you are calling this widget once in a screen. if you are using this widget twice then it will not work because two hero's can’t have same tag in one screen. so, i also suggest you. to assign tag dynamically.
class CustomLogo extends StatelessWidget {
final nameImage;
final radiusImage;
final leftPadding;
CustomLogo({this.leftPadding, this.nameImage, this.radiusImage});
#override
Widget build(BuildContext context) {
return new Hero(
tag: 'hero',
child: Padding(
padding: EdgeInsets.fromLTRB(leftPadding, 70.0, 0.0, 0.0),
child: CircleAvatar(
backgroundColor: Colors.transparent,
radius: radiusImage,
child: Image.asset('assets/' + nameImage),
),
),
);
}
}
How you can call or use this widget.
CustomLogo(leftPadding: 10,radiusImage: 5,nameImage: "hello",)
I need to create icon with two character such as 'Ac' for account, 'Co' for contact, something like as follow:
There is no suitable Icon builder to do that. IconData accept only one char, it make sense, but useful to my case.
I also do not know these two char in advance, so that I could make ImageIcon. How ImageIcon use SVG as source?
I would just use a decorated Container with a Text inside it. You'll probably want to tweak the sizes but here's an example.
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
class TwoLetterIcon extends StatelessWidget {
TwoLetterIcon(this.name, { #required this.color });
/// The background color of the custom icon.
final Color color;
/// The text that will be used for the icon. It is truncated to 2 characters.
final String name;
#override
Widget build(BuildContext context) {
return new Container(
decoration: new BoxDecoration(
color: color,
borderRadius: new BorderRadius.circular(4.0),
),
padding: new EdgeInsets.all(4.0),
height: 30.0,
width: 30.0,
child: new Text(
name.substring(0, 2),
style: Theme.of(context).primaryTextTheme.caption,
),
);
}
}
final Map<String, Color> colors = {
'Accounts': Colors.lightGreen.shade700,
'Contacts': Colors.green.shade700,
};
void main() {
runApp(new MaterialApp(
home: new Scaffold(
body: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: colors.keys.map((String name) {
return new ListTile(
leading: new TwoLetterIcon(name, color: colors[name]),
title: new Text(name),
);
}).toList(),
)
),
));
}
You just need to add two_letter_icon as a dependency in your pubspec.yaml file:
two_letter_icon: ^0.0.1