How to call a ontap fuction in another widget indirectly in flutter? - flutter

I'm using animated container for getting toggle button like in android. Here my code is working for toggle button function perfectly. But what i need is, if i press some other button, toggle button should function. see the below image for your reference(if i press "Press" button it should operate toogle button). Thanks in advance.
https://i.stack.imgur.com/qJpWT.jpg
class DialogExample extends StatefulWidget {
#override
_DialogExampleState createState() => new _DialogExampleState();
}
class _DialogExampleState extends State<DialogExample> {
bool toggleValue = false;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(top:180.0),
child: Center(
child: InkWell(
onTap: toggleButton,
child: AnimatedContainer(
duration: Duration(milliseconds: 100),
height: 40.0,
width: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: toggleValue ? Colors.deepOrangeAccent : Colors.grey.withOpacity(0.5),
),
child: Stack(
children: [
AnimatedPositioned(
duration: Duration(milliseconds: 300),
curve: Curves.easeIn,
left: toggleValue? 60.0 : 0.0,
right: toggleValue ? 0.0 : 60.0,
child: InkWell(
onTap: toggleButton,
child: AnimatedSwitcher(
duration: Duration(milliseconds: 100),
child: toggleValue ? Icon(Icons.check_circle,color: Colors.white,size: 39.0, key: UniqueKey(),)
: Icon(Icons.check_circle,color: Colors.white,size: 39.0,
key: UniqueKey(),),
),
),
)
],
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(top:80.0),
child: RaisedButton(
child: Text("press"),
onPressed: (){
toggleButton;
},
),
)
],
),
);
}
toggleButton() {
setState(() {
toggleValue = !toggleValue;
});
}
}

Replace your button code with the below code block. Actually you are calling toggle button inside a method, So, it is unable to recognition it.
Padding(
padding: const EdgeInsets.only(top:80.0),
child: RaisedButton(
child: Text("press"),
onPressed:toggleButton,
),
)

Just replace toggleButton with, because that is not valid statement here.
toggleButton();

Related

Customize agora video call UI in flutter

my video call output
when logged another person to this video call then shows like this.But I want when someone logged to video call then my video should be small.
like this.
and also when click my video then my video should be big and another person's video should be small. how to do that ? I couldn't find the any documentation how to do that
Code video call ui
// video view
Widget _viewRows() {
final views = _getRenderViews();
switch (views.length) {
case 1:
return Column(
children: <Widget>[_videoView(views[0])],
);
case 2:
return Column(
children: <Widget>[
_expandedVideoRow([views[0]]),
_expandedVideoRow([views[1]])
],
);
case 3:
return Column(
children: <Widget>[
_expandedVideoRow(views.sublist(0, 2)),
_expandedVideoRow(views.sublist(2, 3))
],
);
case 4:
return Column(
children: <Widget>[
_expandedVideoRow(views.sublist(0, 2)),
_expandedVideoRow(views.sublist(2, 4))
],
);
default:
}
return Container();
}
How customize the video UI like as I mentioned?
error
To create the layout which you want, edit _viewRow(CallNotifier notifier) and _expandedVideoRow(List views) function with following code : -
Widget _viewRows(CallNotifier notifier) : -
case 2:
return Container(
margin: EdgeInsets.only(top: 100, bottom: 100),
child: Stack(
children: [
_expandedVideoRow([views[secondScreen]]),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 10, bottom: 10),
child: GestureDetector(
onTap: () {
tempSwap = firstScreen;
firstScreen = secondScreen;
secondScreen = tempSwap;
setState(() {});
},
child: SizedBox(
height: 200,
width: 100,
child: _expandedVideoRow([views[firstScreen]])),
),
),
),
],
));
Above code contains _expandedVideoRow([views[secondScreen]]), which is just a simple Expandable Container and we are passing the index of the screen as a parameter. In our case, there are 2 screens hence 2 index that is 0 and 1. I have declared three integer variables here, int firstScreen = 0, int secondScreen = 1 and int tempSwap = 0. The second _expandedVideoRow([views[firstScreen]]) is wrapped by GesutreDector, so when the user taps on that screen the indexes of the variable are swapped which results in swapping the screens, SizedBox to reduce its width and height and Align widget to give the desired position to the second screen.
Widget _expandedVideoRow(List views) : -
Widget _expandedVideoRow(List<Widget> views) {
final wrappedViews = views.map<Widget>(_videoView).toList();
return Row(
children: wrappedViews,
);
}
Remove the Expanded widget that wraps the row like the above code because we can't use the Expanded under the Stack widget.
If you wish to change the bottom icons, then change _toolbar(CallNotifier notifier) function according to your need.
Widget _toolbar(CallNotifier notifier) {
return Container(
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RawMaterialButton(
onPressed: () {
_onToggleMute(notifier);
setState(() {
isMute = !isMute;
});
},
child: Icon(
isMute ? Icons.mic_off : Icons.mic,
color: isMute ? Colors.white : Colors.teal,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: isMute ? Colors.teal : Colors.white,
padding: const EdgeInsets.all(12.0),
),
RawMaterialButton(
onPressed: () => _onCallEnd(context),
child: Icon(
Icons.call_end,
color: Colors.white,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: Colors.redAccent,
padding: const EdgeInsets.all(15.0),
),
],
),
);
}
Code which I use in my app, full code : -
class _CallScreenState extends State<CallScreen> {
double globalHeight;
int firstScreen = 0;
int secondScreen = 1;
int tempSwap = 0;
bool isMute = false;
void initState() {
super.initState();
}
List<Widget> _getRenderViews(CallNotifier model) {
final List<StatefulWidget> list = [];
list.add(RtcLocalView.SurfaceView());
model.users
.forEach((int uid) => list.add(RtcRemoteView.SurfaceView(uid: uid)));
return list;
}
Widget _videoView(view) {
return Expanded(child: Container(child: view));
}
Widget _expandedVideoRow(List<Widget> views) {
final wrappedViews = views.map<Widget>(_videoView).toList();
return Row(
children: wrappedViews,
);
}
Widget _viewRows(CallNotifier notifier) {
final views = _getRenderViews(notifier);
switch (views.length) {
case 1:
return Container(
margin: EdgeInsets.only(top: 100, bottom: 100),
child: Column(
children: <Widget>[_videoView(views[0])],
));
case 2:
return Container(
margin: EdgeInsets.only(top: 100, bottom: 100),
child: Stack(
children: [
_expandedVideoRow([views[secondScreen]]),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 10, bottom: 10),
child: GestureDetector(
onTap: () {
tempSwap = firstScreen;
firstScreen = secondScreen;
secondScreen = tempSwap;
setState(() {});
},
child: SizedBox(
height: 200,
width: 100,
child: _expandedVideoRow([views[firstScreen]])),
),
),
),
],
));
default:
}
return Container();
}
Widget _toolbar(CallNotifier notifier) {
return Container(
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RawMaterialButton(
onPressed: () {
_onToggleMute(notifier);
setState(() {
isMute = !isMute;
});
},
child: Icon(
isMute ? Icons.mic_off : Icons.mic,
color: isMute ? Colors.white : Colors.teal,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: isMute ? Colors.teal : Colors.white,
padding: const EdgeInsets.all(12.0),
),
RawMaterialButton(
onPressed: () => _onCallEnd(context),
child: Icon(
Icons.call_end,
color: Colors.white,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: Colors.redAccent,
padding: const EdgeInsets.all(15.0),
),
],
),
);
}
void _onCallEnd(BuildContext context) {
Navigator.pop(context);
}
void _onToggleMute(CallNotifier notifier) {
notifier.isMuted = notifier.isMuted;
notifier.engine.muteLocalAudioStream(notifier.isMuted);
}
#override
Widget build(BuildContext context) {
return BaseWidget<CallNotifier>(
model: CallNotifier(),
onModelReady: (model) => model.init(widget.channelName, widget.token),
builder: (context, notifier, child) {
return Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child: Stack(
children: <Widget>[
_viewRows(notifier),
Align(
alignment: Alignment.bottomCenter,
child: _toolbar(notifier)),
],
),
),
);
});
}
}

Transition from large to small image smooth animation - Flutter

I have a login-page where I want the transition of the logo from large to small (and back) to be smoother. As it is now, it just pops between the two.
When the keyboard opens, I would like the logo to animate to the smaller position, instead of just instantly changing.
Does anyone know a way to do this?
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: AppColors.yellowLight,
// appBar: MainAppBar(),
body: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
padding: EdgeInsets.symmetric(vertical: 90),
child: Image(
image: ExactAssetImage('assets/icons/app_logo.png'),
height: MediaQuery.of(context).viewInsets.bottom == 0
? size.height * 0.3
: size.height * 0.15,
fit: BoxFit.fitHeight,
alignment: Alignment.center,
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 50),
child: MainTextField(
controller: emailController,
labelText: 'E-post',
hintText: 'Skriv e-post som abc#epost.no'),
),
Padding(
padding: const EdgeInsets.only(
left: 50.0, right: 50.0, top: 30, bottom: 30),
child: MainTextField(
controller: passwordController,
obscureText: true,
labelText: 'Passord',
hintText: 'Skriv inn sikkert passord',
),
),
LoginButton(
text: 'Logg inn',
isLoading: isLoading,
onPressed: _login,
),
// Text('New User? Create Account')
],
),
),
),
);
}
AnimatedContainer(
height: MediaQuery.of(context).viewInsets.bottom != 0 ? 100.0 : 200.0,
width: MediaQuery.of(context).viewInsets.bottom != 0 ? 100 : 200.0,
duration:const Duration(milliseconds: 750),
curve: Curves.fastOutSlowIn,
child: Image.network("https://picsum.photos/200/300"),
),
but MediaQuery.of(context).viewInsets.bottom it won't give you accuracy as if it's real time when changing the keyboard state, so I advice you to use another method to know the current state of the keyboard like the code below
you can use this package to listen for keyboard change flutter_keyboard_visibility here is the code
class _MyHomePageState extends State<MyHomePage> {
late StreamSubscription<bool> keyboardSubscription;
bool _isVisible = false;
#override
void initState() {
super.initState();
var keyboardVisibilityController = KeyboardVisibilityController();
// Subscribe
keyboardSubscription = keyboardVisibilityController.onChange.listen((bool visible) {
if(mounted) {
setState(() {
_isVisible = visible;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AnimatedContainer(
height: _isVisible ? 100.0 : 200.0,
width: _isVisible ? 100 : 200.0,
duration:const Duration(milliseconds: 750),
curve: Curves.fastOutSlowIn,
child: Image.network("https://picsum.photos/200/300"),
),
Spacer(),
const Text(
'You have pushed the button this many times:',
),
TextFormField(
),
Spacer(),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){},
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
#override
void dispose() {
keyboardSubscription.cancel();
super.dispose();
}
}
if you don't want to use package for keyboard visibility so you can use this code
class _MyHomePageState extends State<MyHomePage> {
final FocusNode _myNode = FocusNode();
bool _isVisible = false;
#override
void initState() {
super.initState();
_myNode.addListener(_listener);
}
void _listener(){
if(_myNode.hasFocus){
// keyboard appeared
if(mounted){
setState(() {
_isVisible = true;
});
}
}else{
// keyboard dismissed
if(mounted){
setState(() {
_isVisible = false;
});
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AnimatedContainer(
height: _isVisible ? 100.0 : 200.0,
width: _isVisible ? 100 : 200.0,
duration:const Duration(milliseconds: 750),
curve: Curves.fastOutSlowIn,
child: Image.network("https://picsum.photos/200/300"),
),
Spacer(),
const Text(
'You have pushed the button this many times:',
),
TextFormField(
focusNode: _myNode,
),
Spacer(),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){},
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
#override
void dispose() {
_myNode.removeListener(_listener);
super.dispose();
}
}
I found a way that kind of works. At least the animation does. But as it is based on MediaQuery.of(context).viewInsets.bottom == 0 still, the animation does not start until the keyboard is all the way out of view.
AnimatedContainer(
duration: Duration(milliseconds: 400),
curve: Curves.fastOutSlowIn,
padding: MediaQuery.of(context).viewInsets.bottom == 0
? EdgeInsets.symmetric(vertical: 100)
: EdgeInsets.only(top: 75, bottom: 10),
height: MediaQuery.of(context).viewInsets.bottom == 0
? _height.height * 0.5
: _height.height * 0.25,
child: Image(
image: ExactAssetImage('assets/icons/app_logo.png'),
),
),

Flutter: Color expand from the side to fill container

I currently have a card widget with two animated containers of different colors. When the user clicks on either color, the other side of the container changes to match the users selection.
When the user clicks on a side, I want the color to expand out and fill about 90% of the card still showing just a sliver of the previous color. So for example if the card started out with red on the left and blue on the right, after clicking on the blue side, the blue would expand from right to left covering 90% of the card and the red would cover the remaining 10% on the left.
I hope that made sense. I am new to flutter so still just learning.
class _PickState extends State<Pick> {
Color _colorA = Colors.red;
Color _colorB = Colors.blue;
#override
Widget build(BuildContext context) {
return Card(
child: Row(
children: <Widget>[
Expanded(
child: GestureDetector(
child: AnimatedContainer(
color: _colorA,
child: const Text("Option A"),
alignment: Alignment.centerLeft,
constraints: const BoxConstraints(minHeight: 75),
duration: const Duration(milliseconds: 250),
),
onTap: () {
_clickA();
},
),
),
Expanded(
child: GestureDetector(
child: AnimatedContainer(
color: _colorB,
child: const Text("Option B"),
alignment: Alignment.centerRight,
constraints: const BoxConstraints(minHeight: 75),
duration: const Duration(milliseconds: 250),
),
onTap: () {
_clickB();
},
))
],
),
);
}
void _clickA() {
setState(() {
_colorA = Colors.red;
_colorB = Colors.red;
});
}
void _clickB() {
setState(() {
_colorA = Colors.blue;
_colorB = Colors.blue;
});
}
}
class _PickState extends State<Pick> {
int _colorAPercentage = 90;
int _colorBPercentage = 10;
#override
Widget build(BuildContext context) {
return Card(
child: Row(
children: <Widget>[
Expanded(
flex: _colorAPercentage,
child: GestureDetector(
child: AnimatedContainer(
color: Colors.red,
child: const Text("Option A"),
alignment: Alignment.centerLeft,
constraints: const BoxConstraints(minHeight: 75),
duration: const Duration(milliseconds: 250),
),
onTap: () {
_clickA();
},
),
),
Expanded(
flex: _colorBPercentage,
child: GestureDetector(
child: AnimatedContainer(
color: Colors.blue,
child: const Text("Option B"),
alignment: Alignment.centerRight,
constraints: const BoxConstraints(minHeight: 75),
duration: const Duration(milliseconds: 250),
),
onTap: () {
_clickB();
},
))
],
),
);
}
void _clickA() {
setState(() {
_colorAPercentage = 90;
_colorBPercentage = 10;
});
}
void _clickB() {
setState(() {
_colorAPercentage = 10;
_colorBPercentage = 90;
});
}
}
If I understood correctly, try this.
#override
Widget build(BuildContext context) {
return Card(
child: Row(
children: <Widget>[
Expanded(
child: GestureDetector(
child: AnimatedContainer(
color: Colors.red,
duration: const Duration(milliseconds: 250),
),
onTap: () {
_clickA();
},
),
),
Expanded(
flex: 4,
child: GestureDetector(
child: AnimatedContainer(
color: _colorA,
child: const Text("Option A"),
alignment: Alignment.centerLeft,
constraints: const BoxConstraints(minHeight: 75),
duration: const Duration(milliseconds: 250),
),
onTap: () {
_clickA();
},
),
),
Expanded(
flex: 4,
child: GestureDetector(
child: AnimatedContainer(
color: _colorB,
child: const Text("Option B"),
alignment: Alignment.centerRight,
constraints: const BoxConstraints(minHeight: 75),
duration: const Duration(milliseconds: 250),
),
onTap: () {
_clickB();
},
)),
Expanded(
child: GestureDetector(
child: AnimatedContainer(
color: Colors.blue,
duration: const Duration(milliseconds: 250),
),
onTap: () {
_clickB();
},
))
],
),
);
}

Floating button not changing positioned

I'm having trouble in figuring out how to fix a floating button in the right place.
I've tried several things, but without success.
This is how It's currenlty looking.
and the code
Widget myButtonTest(MediaQueryData mediaQuery){
Widget child;
if (widget.button == "video"){
return Column(
children: <Widget>[
Center(
child: Padding(
padding: const EdgeInsets.only(top: 80.0),
child: ClipPath(
child: Container(
child:AspectRatio(
aspectRatio: 1,
child: VideoPlayer(_controller),
)
),
clipper: BottomWaveClipper(),
))),
FloatingActionButton(
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child:Icon(
Icons.play_arrow,
color: Colors.red,
size: 32.0,
),
backgroundColor: Colors.white,
),
]
);
}
return Container(child: child);
}
And this is where I want the button.
Try wrapping the floating action button with padding, and having the padding be:
padding: const EdgeInsets.fromLTRB(0,0,0,100),
Also make sure the padding is on the Floating action button like this:
Padding(
padding: const EdgeInsets.fromLTRB(0,0,0,100),
child: FloatingActionButton(

Flutter : Widget Switch Between Animation

I trying to do animation for widget switching position. Image below show A and B widget, I would like to switch between A to B / B to A when button clicked. But at first I have no clue where to start, I wonder is there any plugin are able to achieve, any suggestion could help me, just and some tips, I willing to study the suggestion plugin.
I tried using AnimatedAlign
Container(
height: 120.0,
color: Colors.black,
child: Column(
children: [
AnimatedAlign(
alignment: _alignment.value = _alignment.value == Alignment.topCenter ? Alignment.bottomCenter : _alignment.value,
curve: Curves.ease,
duration: Duration(milliseconds: 500),
child: Padding(
padding: EdgeInsets.all(2.5),
child: Container(
height: 55,
color: Colors.red,
),
)
),
AnimatedAlign(
alignment: _alignment.value = _alignment.value == Alignment.bottomCenter ? Alignment.topCenter : _alignment.value,
curve: Curves.ease,
duration: Duration(milliseconds: 500),
child: Padding(
padding: EdgeInsets.all(2.5),
child: Container(
height: 55,
color: Colors.blue,
),
),
)
],
),
),
RaisedButton(
onPressed: () {
_alignment.value = Alignment.bottomCenter;
},
child: Text("Switch Position"),
)
I Created an Example ... this is working.I used Animation Positioned
import 'package:flutter/material.dart';
void main() {
runApp(MyClass());
}
class MyClass extends StatefulWidget {
#override
_MyClassState createState() => _MyClassState();
}
class _MyClassState extends State<MyClass>{
bool change = true;
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(title: Text('Title')),
body: Stack(
children: <Widget>[
AnimatedPositioned(
top: change ? 50 : 150,
left: 50,
right: 50,
duration: Duration(milliseconds: 300),
child: red()
),
AnimatedPositioned(
top: change ? 150 : 50,
left: 50,
right: 50,
duration: Duration(milliseconds: 300),
child: blue()
),
Positioned(
top: 210,
left: 50,
right: 50,
child: Center(
child: InkWell(
onTap: (){
setState(() {
change = !change;
});
},
child: Container(
color: Colors.amber,
width: 65,
height: 50,
child: Center(child: Text("click me")),
),
),
),
)
],
),
),
);
}
}
red(){
return Container(
width: 120,
height: 50,
color: Colors.red,
);
}
blue(){
return Container(
width: 120,
height: 50,
color: Colors.blue,
);
}