Flutter expand TextField using dragging and button click - flutter

How can I increase/decrease the number of maxLines in TextField with dragging and clicking button?

Screenshot:
Full code:
class YourPage extends StatefulWidget {
#override
_YourPageState createState() => _YourPageState();
}
class _YourPageState extends State<YourPage> {
double _maxHeight = 200, _minHeight = 44, _height = 44, _dividerHeight = 56, _offset = 19;
int _maxLines = 1;
static final Duration _fixDuration = Duration(milliseconds: 500);
Duration _duration = _fixDuration;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(20),
child: SizedBox(
height: _maxHeight,
child: Column(
children: <Widget>[
AnimatedContainer(
duration: _duration,
height: _height,
child: TextField(
decoration: InputDecoration(hintText: "Enter a message"),
maxLines: _maxLines,
),
),
Container(
height: _dividerHeight,
width: 200,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_downward),
onPressed: () {
if (_height <= _maxHeight - _offset - _dividerHeight) {
setState(() {
_duration = _fixDuration;
_height += _offset;
_maxLines++;
});
}
},
),
GestureDetector(
child: Icon(Icons.drag_handle),
onPanUpdate: (details) {
setState(() {
_height += details.delta.dy;
_duration = Duration.zero;
// prevent overflow if height is more/less than available space
var maxLimit = _maxHeight - _dividerHeight;
var minLimit = 44.0;
if (_height > maxLimit)
_height = maxLimit;
else if (_height < minLimit) _height = minLimit;
_maxLines = 100;
});
},
),
IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () {
if (_height >= _minHeight + _offset) {
setState(() {
_duration = _fixDuration;
_height -= _offset;
});
}
},
),
],
),
)
],
),
),
),
);
}
}

Related

Video player play image and video looping flutter

can video player play image for 10sec then loop to next video ?
How can i loop image only for 10sec then loop into next new video in my video clip data or video player controller ?
I manage to add video to video player but don't know how to add image to the player.
video clip data
class VideoClip {
final String fileName;
final String thumbName;
final String title;
final String parent;
int runningTime;
VideoClip(this.title, this.fileName, this.thumbName, this.runningTime, this.parent);
String videoPath() {
return "$parent/$fileName";
}
String thumbPath() {
return "$parent/$thumbName";
}
static List<VideoClip> remoteClips = [
VideoClip("For Bigger Fun", "ForBiggerFun.mp4", "images/ForBiggerFun.jpg", 0, "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample"),
VideoClip("Elephant Dream", "ElephantsDream.mp4", "images/ForBiggerBlazes.jpg", 0, "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample"),
VideoClip("BigBuckBunny", "BigBuckBunny.mp4", "images/BigBuckBunny.jpg", 0, "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample"),
];
}
Video player controller
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_video_list_sample/clips.dart';
import 'package:video_player/video_player.dart';
import 'package:wakelock/wakelock.dart';
class PlayPage extends StatefulWidget {
PlayPage({Key key, #required this.clips}) : super(key: key);
final List<VideoClip> clips;
#override
_PlayPageState createState() => _PlayPageState();
}
class _PlayPageState extends State<PlayPage> {
VideoPlayerController _controller;
List<VideoClip> get _clips {
return widget.clips;
}
var _playingIndex = -1;
var _disposed = false;
var _isFullScreen = false;
var _isEndOfClip = false;
var _progress = 0.0;
var _showingDialog = false;
Timer _timerVisibleControl;
double _controlAlpha = 1.0;
var _playing = false;
bool get _isPlaying {
return _playing;
}
set _isPlaying(bool value) {
_playing = value;
_timerVisibleControl?.cancel();
if (value) {
_timerVisibleControl = Timer(Duration(seconds: 2), () {
if (_disposed) return;
setState(() {
_controlAlpha = 0.0;
});
});
} else {
_timerVisibleControl = Timer(Duration(milliseconds: 200), () {
if (_disposed) return;
setState(() {
_controlAlpha = 1.0;
});
});
}
}
void _onTapVideo() {
debugPrint("_onTapVideo $_controlAlpha");
setState(() {
_controlAlpha = _controlAlpha > 0 ? 0 : 1;
});
_timerVisibleControl?.cancel();
_timerVisibleControl = Timer(Duration(seconds: 2), () {
if (_isPlaying) {
setState(() {
_controlAlpha = 0.0;
});
}
});
}
#override
void initState() {
Wakelock.enable();
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
_initializeAndPlay(0);
super.initState();
}
#override
void dispose() {
_disposed = true;
_timerVisibleControl?.cancel();
Wakelock.disable();
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
_exitFullScreen();
_controller?.pause(); // mute instantly
_controller?.dispose();
_controller = null;
super.dispose();
}
void _toggleFullscreen() async {
if (_isFullScreen) {
_exitFullScreen();
} else {
_enterFullScreen();
}
}
void _enterFullScreen() async {
debugPrint("enterFullScreen");
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
await SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
if (_disposed) return;
setState(() {
_isFullScreen = true;
});
}
void _exitFullScreen() async {
debugPrint("exitFullScreen");
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
if (_disposed) return;
setState(() {
_isFullScreen = false;
});
}
void _initializeAndPlay(int index) async {
print("_initializeAndPlay ---------> $index");
final clip = _clips[index];
final controller = clip.parent.startsWith("http")
? VideoPlayerController.network(clip.videoPath())
: VideoPlayerController.asset(clip.videoPath());
final old = _controller;
_controller = controller;
if (old != null) {
old.removeListener(_onControllerUpdated);
old.pause();
debugPrint("---- old contoller paused.");
}
debugPrint("---- controller changed.");
setState(() {});
controller
..initialize().then((_) {
debugPrint("---- controller initialized");
old?.dispose();
_playingIndex = index;
_duration = null;
_position = null;
controller.addListener(_onControllerUpdated);
controller.play();
setState(() {});
});
}
var _updateProgressInterval = 0.0;
Duration _duration;
Duration _position;
void _onControllerUpdated() async {
if (_disposed) return;
// blocking too many updation
// important !!
final now = DateTime.now().millisecondsSinceEpoch;
if (_updateProgressInterval > now) {
return;
}
_updateProgressInterval = now + 500.0;
final controller = _controller;
if (controller == null) return;
if (!controller.value.isInitialized) return;
if (_duration == null) {
_duration = _controller.value.duration;
}
var duration = _duration;
if (duration == null) return;
var position = await controller.position;
_position = position;
final playing = controller.value.isPlaying;
final isEndOfClip = position.inMilliseconds > 0 && position.inSeconds + 1 >= duration.inSeconds;
if (playing) {
// handle progress indicator
if (_disposed) return;
setState(() {
_progress = position.inMilliseconds.ceilToDouble() / duration.inMilliseconds.ceilToDouble();
});
}
// handle clip end
if (_isPlaying != playing || _isEndOfClip != isEndOfClip) {
_isPlaying = playing;
_isEndOfClip = isEndOfClip;
debugPrint("updated -----> isPlaying=$playing / isEndOfClip=$isEndOfClip");
if (isEndOfClip && !playing) {
debugPrint("========================== End of Clip / Handle NEXT ========================== ");
final isComplete = _playingIndex == _clips.length - 1;
if (isComplete) {
print("played all!!");
if (!_showingDialog) {
_showingDialog = true;
_showPlayedAllDialog().then((value) {
_exitFullScreen();
_showingDialog = false;
});
}
} else {
_initializeAndPlay(_playingIndex + 1);
}
}
}
}
Future<bool> _showPlayedAllDialog() async {
return showDialog<bool>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
content: SingleChildScrollView(child: Text("Played all videos.")),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text("Close"),
),
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _isFullScreen
? null
: AppBar(
title: Text("Play View"),
),
body: _isFullScreen
? Container(
child: Center(child: _playView(context)),
decoration: BoxDecoration(color: Colors.black),
)
: Column(children: <Widget>[
Container(
child: Center(child: _playView(context)),
decoration: BoxDecoration(color: Colors.black),
),
Expanded(
child: _listView(),
),
]),
);
}
void _onTapCard(int index) {
_initializeAndPlay(index);
}
Widget _playView(BuildContext context) {
final controller = _controller;
if (controller != null && controller.value.isInitialized) {
return AspectRatio(
//aspectRatio: controller.value.aspectRatio,
aspectRatio: 16.0 / 9.0,
child: Stack(
children: <Widget>[
GestureDetector(
child: VideoPlayer(controller),
onTap: _onTapVideo,
),
_controlAlpha > 0
? AnimatedOpacity(
opacity: _controlAlpha,
duration: Duration(milliseconds: 250),
child: _controlView(context),
)
: Container(),
],
),
);
} else {
return AspectRatio(
aspectRatio: 16.0 / 9.0,
child: Center(
child: Text(
"Preparing ...",
style: TextStyle(color: Colors.white70, fontWeight: FontWeight.bold, fontSize: 18.0),
)),
);
}
}
Widget _listView() {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
itemCount: _clips.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
borderRadius: BorderRadius.all(Radius.circular(6)),
splashColor: Colors.blue[100],
onTap: () {
_onTapCard(index);
},
child: _buildCard(index),
);
},
).build(context);
}
Widget _controlView(BuildContext context) {
return Column(
children: <Widget>[
_topUI(),
Expanded(
child: _centerUI(),
),
_bottomUI()
],
);
}
Widget _centerUI() {
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: () async {
final index = _playingIndex - 1;
if (index > 0 && _clips.length > 0) {
_initializeAndPlay(index);
}
},
child: Icon(
Icons.fast_rewind,
size: 36.0,
color: Colors.white,
),
),
TextButton(
onPressed: () async {
if (_isPlaying) {
_controller?.pause();
_isPlaying = false;
} else {
final controller = _controller;
if (controller != null) {
final pos = _position?.inSeconds ?? 0;
final dur = _duration?.inSeconds ?? 0;
final isEnd = pos == dur;
if (isEnd) {
_initializeAndPlay(_playingIndex);
} else {
controller.play();
}
}
}
setState(() {});
},
child: Icon(
_isPlaying ? Icons.pause : Icons.play_arrow,
size: 56.0,
color: Colors.white,
),
),
TextButton(
onPressed: () async {
final index = _playingIndex + 1;
if (index < _clips.length - 1) {
_initializeAndPlay(index);
}
},
child: Icon(
Icons.fast_forward,
size: 36.0,
color: Colors.white,
),
),
],
));
}
String convertTwo(int value) {
return value < 10 ? "0$value" : "$value";
}
Widget _topUI() {
final noMute = (_controller?.value?.volume ?? 0) > 0;
final duration = _duration?.inSeconds ?? 0;
final head = _position?.inSeconds ?? 0;
final remained = max(0, duration - head);
final min = convertTwo(remained ~/ 60.0);
final sec = convertTwo(remained % 60);
return Row(
children: <Widget>[
InkWell(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Container(
decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
BoxShadow(offset: const Offset(0.0, 0.0), blurRadius: 4.0, color: Color.fromARGB(50, 0, 0, 0)),
]),
child: Icon(
noMute ? Icons.volume_up : Icons.volume_off,
color: Colors.white,
)),
),
onTap: () {
if (noMute) {
_controller?.setVolume(0);
} else {
_controller?.setVolume(1.0);
}
setState(() {});
},
),
Expanded(
child: Container(),
),
Text(
"$min:$sec",
style: TextStyle(
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(0.0, 1.0),
blurRadius: 4.0,
color: Color.fromARGB(150, 0, 0, 0),
),
],
),
),
SizedBox(width: 10)
],
);
}
Widget _bottomUI() {
return Row(
children: <Widget>[
SizedBox(width: 20),
Expanded(
child: Slider(
value: max(0, min(_progress * 100, 100)),
min: 0,
max: 100,
onChanged: (value) {
setState(() {
_progress = value * 0.01;
});
},
onChangeStart: (value) {
debugPrint("-- onChangeStart $value");
_controller?.pause();
},
onChangeEnd: (value) {
debugPrint("-- onChangeEnd $value");
final duration = _controller?.value?.duration;
if (duration != null) {
var newValue = max(0, min(value, 99)) * 0.01;
var millis = (duration.inMilliseconds * newValue).toInt();
_controller?.seekTo(Duration(milliseconds: millis));
_controller?.play();
}
},
),
),
IconButton(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
color: Colors.yellow,
icon: Icon(
Icons.fullscreen,
color: Colors.white,
),
onPressed: _toggleFullscreen,
),
],
);
}
Widget _buildCard(int index) {
final clip = _clips[index];
final playing = index == _playingIndex;
String runtime;
if (clip.runningTime > 60) {
runtime = "${clip.runningTime ~/ 60}분 ${clip.runningTime % 60}초";
} else {
runtime = "${clip.runningTime % 60}초";
}
return Card(
child: Container(
padding: EdgeInsets.all(4),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.only(right: 8),
child: clip.parent.startsWith("http")
? Image.network(clip.thumbPath(), width: 70, height: 50, fit: BoxFit.fill)
: Image.asset(clip.thumbPath(), width: 70, height: 50, fit: BoxFit.fill),
),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(clip.title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Padding(
child: Text("$runtime", style: TextStyle(color: Colors.grey[500])),
padding: EdgeInsets.only(top: 3),
)
]),
),
Padding(
padding: EdgeInsets.all(8.0),
child: playing
? Icon(Icons.play_arrow)
: Icon(
Icons.play_arrow,
color: Colors.grey.shade300,
),
),
],
),
),
);
}
}

Flutter Resizable Container using Gestures

I want to create a resizable container which can be resized by user using horizontal drag.
This Gif can explain the requirement:
I tried GestureDetector.horizontal drag but the results are way off:
Container(
color: primary,
width: size.width,
height: 40,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onHorizontalDragUpdate: (details) {
final double newWidth;
if (details.delta.dx > 0) {
// movement in positive direction
final newWidth = size.width + 1;
print(newWidth);
final updatedSize = Size(newWidth, size.height);
setState(() {
size = updatedSize;
});
} else {
// movement in negative direction
final newWidth = math.max(size.width - 1, 5).toDouble();
print(newWidth);
final updatedSize = Size(newWidth, size.height);
setState(() {
size = updatedSize;
});
}
},
child: const Icon(
Icons.navigate_before_rounded,
color: Colors.white,
),
),
GestureDetector(
onHorizontalDragUpdate: (det) {
if (det.delta.dx > 1) {
var newWidth = size.width + 1;
final updatedSize = Size(newWidth, size.height);
setState(() {
size = updatedSize;
});
} else {
var newWidth = size.width - 1;
newWidth = math.max(newWidth, 10);
final updatedSize = Size(newWidth, size.height);
setState(() {
size = updatedSize;
});
}
},
child: const Icon(
Icons.navigate_next_rounded,
color: Colors.white,
),
),
],
),
),
I am looking for a way to get size change of one side using drag, also the width should decrease or increase on the basis of dragging direction and if possible the whole container can be moved as well.
You can use Stack with Positioned widget to handle container sizing and to drag the full container I am using transform.
Run on dartPad
You can play with this widget.
class FContainer extends StatefulWidget {
FContainer({Key? key}) : super(key: key);
#override
State<FContainer> createState() => _FContainerState();
}
class _FContainerState extends State<FContainer> {
///initial position
double leftPos = 33;
double rightPos = 33;
double transformX = 0;
#override
Widget build(BuildContext context) {
return Center(
child: LayoutBuilder(
builder: (context, constraints) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
transform: Matrix4.translationValues(transformX, 0, 0),
height: 60,
width: constraints.maxWidth,
child: Stack(
children: [
Positioned(
top: 0,
bottom: 0,
left: leftPos,
right: rightPos,
child: Row(
children: [
GestureDetector(
onTap: () {},
onHorizontalDragUpdate: (details) {
leftPos = details.globalPosition.dx;
setState(() {});
debugPrint(leftPos.toString());
},
child: Container(
height: 60,
color: Colors.purple,
child: const Icon(
Icons.navigate_next_rounded,
color: Colors.black,
),
),
),
Expanded(
child: GestureDetector(
onTap: () {},
onHorizontalDragUpdate: (details) {
final midPos = details.delta;
transformX += midPos.dx;
setState(() {});
debugPrint(midPos.toString());
},
child: Container(
color: Colors.purple,
),
),
),
GestureDetector(
onTap: () {},
onHorizontalDragUpdate: (details) {
rightPos = constraints.maxWidth -
details.globalPosition.dx;
setState(() {});
debugPrint(rightPos.toString());
},
child: Container(
height: 60,
color: Colors.purple,
child: const Icon(
Icons.navigate_before_rounded,
color: Colors.black,
),
),
),
],
),
)
],
),
)
],
),
),
);
}
}
You can wrap with if condition to avoid getting out of the screen.

AutoScroll Text with pinch and zoom in flutter

I'm new to flutter and I'm trying to implement a page where I want to show Text Widget with AutoScroll Also users can Zoom in and Zoom Out the text. I have implemented AutoScroll using the help of this link (AutoScroll Text). I have also added GestureDetector but It's not working as expected. Here is the complete source code which I have right now...
import 'dart:async';
import 'dart:ui';
import 'package:ffmpeg_demo/Utility/util.dart';
import 'package:flutter/material.dart';
class PDFViewer extends StatefulWidget {
final Function() onDismissTapped;
final String pdfText;
const PDFViewer(
{Key? key, required this.onDismissTapped, required this.pdfText})
: super(key: key);
#override
State<PDFViewer> createState() => _PDFViewerState();
}
class _PDFViewerState extends State<PDFViewer> {
double scrollSpeed = 1.0;
Function? onDismissTapped;
//https://stackoverflow.com/questions/57138772/how-to-autoscroll-text-in-flutter
final ScrollController _scrollController = ScrollController();
bool scroll = false;
int speedFactor = 100;
//For Scaling Text Area
//https://stackoverflow.com/questions/55440184/flutter-gesturedetector-how-to-pinch-in-out-or-zoom-in-out-text-using-two-finge
double _fontSize = 20;
final double _baseFontSize = 20;
double _fontScale = 1;
double _baseFontScale = 1;
double _scaleFactor = 1.0;
double _baseScaleFactor = 1.0;
bool _stopScrolling = false;
_scroll() {
double maxExtent = _scrollController.position.maxScrollExtent;
double distanceDifference = maxExtent - _scrollController.offset;
double durationDouble = distanceDifference / speedFactor;
int duration = durationDouble.toInt();
if (duration <= 0) {
duration = 1;
}
print(
"maxScrollExtent = $maxExtent and distanceDifference = $distanceDifference and durationDouble = $durationDouble");
_scrollController.animateTo(_scrollController.position.maxScrollExtent,
duration: Duration(seconds: duration), curve: Curves.linear);
}
_toggleScrolling() {
/* if (_stopScrolling) {
print("Stop scrolling flag value is $_stopScrolling");
return;
} */
setState(() {
scroll = !scroll;
});
if (scroll) {
_scroll();
} else {
_scrollController.animateTo(_scrollController.offset,
duration: const Duration(seconds: 1), curve: Curves.linear);
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
Future.delayed(const Duration(seconds: 1), () {
_toggleScrolling();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Container(
color: Colors.transparent,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
color: Colors.black.withOpacity(0.5),
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 50, 10, 100),
child: NotificationListener(
onNotification: (notif) {
if (notif is ScrollEndNotification && scroll) {
Timer(const Duration(seconds: 1), () {
_scroll();
});
}
return true;
},
child: SingleChildScrollView(
controller: _scrollController,
scrollDirection: Axis.vertical,
padding: const EdgeInsets.all(20),
child: DefaultTextStyle(
style: const TextStyle(color: Colors.white),
child: GestureDetector(
onScaleStart: (ScaleStartDetails scaleStartDetails) {
setState(() {
//_stopScrolling = true;
_toggleScrolling();
});
//_baseScaleFactor = _scaleFactor;
_baseFontScale = _fontScale;
print("base scale factor = $_baseFontScale");
},
onScaleUpdate:
(ScaleUpdateDetails scaleUpdateDetails) {
// don't update the UI if the scale didn't change
/* if (scaleUpdateDetails.scale == 1.0) {
debugPrint("Scale is 1.0 returning");
setState(() {
_stopScrolling = false;
_toggleScrolling();
});
return;
} */
/* _scaleFactor =
_baseScaleFactor * scaleUpdateDetails.scale;
print("Final scale factor = $_scaleFactor");
if (_scaleFactor < 1.0) {
_scaleFactor = 1.0;
}
print("New Final scale factor = $_scaleFactor"); */
//setState(() {
_fontScale =
(_baseFontScale * scaleUpdateDetails.scale)
.clamp(0.5, 5.0);
_fontSize = _fontScale * _baseFontSize;
debugPrint("New Final font size = $_fontSize");
if (_fontSize < 20) {
_fontSize = 20;
}
//});
setState(() {
//_toggleScrolling();
_stopScrolling = false;
_toggleScrolling();
});
},
child: Text(
widget.pdfText,
/* textScaleFactor:
(_scaleFactor <= 0.1) ? 1.0 : _scaleFactor, */
style: TextStyle(
fontSize: (_fontSize < 20) ? 20 : _fontSize),
),
),
),
),
),
),
Positioned(
bottom: 0,
child: Container(
height: 100,
width: deviceWidth(context),
color: Colors.black.withAlpha(50),
child: Stack(
children: [
Positioned(
bottom: 0,
width: deviceWidth(context),
child: Center(
child: TextButton(
child: const Text(
"Dismiss",
style: TextStyle(color: Colors.white),
),
onPressed: () => widget.onDismissTapped(),
),
),
),
Positioned(
top: 0,
width: deviceWidth(context),
child: Container(
height: 50,
width: deviceWidth(context),
child: _buildSlider(context)),
),
],
),
),
),
],
),
),
),
),
);
}
Widget _buildSlider(BuildContext context) {
return Container(
width: deviceWidth(context),
child: SliderTheme(
data: SliderThemeData(
activeTrackColor: Colors.brown[700],
inactiveTrackColor: Colors.brown[300],
inactiveTickMarkColor: Colors.transparent,
activeTickMarkColor: Colors.transparent),
child: Slider(
divisions: 100,
min: 0,
max: 100,
value: speedFactor.toDouble(),
onChanged: (double value) {
setState(() {
//scrollSpeed = value;
_toggleScrolling();
});
speedFactor = value.toInt();
if (speedFactor == 0) {
speedFactor = 1;
}
Future.delayed(const Duration(seconds: 1), () {
setState(() {
//scrollSpeed = value;
_toggleScrolling();
});
});
}),
),
);
}
}

How to create a list of icons on a vertical arc in Flutter?

I am trying to implement this particular dribbble design in Flutter. Any hints on how to proceed?
As #pskink Suggested, I have tried Flow widget. Let me know If anyone have better idea.
FlowMenu Statefulwidget
class FlowMenu extends StatefulWidget {
#override
_FlowMenuState createState() => _FlowMenuState();
}
class _FlowMenuState extends State<FlowMenu>
with SingleTickerProviderStateMixin {
AnimationController menuAnimation;
IconData lastTapped = Icons.notifications;
void _updateMenu(IconData icon) {
if (icon != Icons.menu) setState(() => lastTapped = icon);
}
#override
void initState() {
super.initState();
menuAnimation = AnimationController(
duration: const Duration(milliseconds: 250),
vsync: this,
);
menuAnimation.addListener(() {
setState(() {});
});
}
Widget flowMenuItem(MenuData menuData) {
return Row(
children: <Widget>[
RawMaterialButton(
fillColor:
lastTapped == menuData.iconData ? Colors.amber[700] : Colors.blue,
splashColor: Colors.amber[100],
shape: CircleBorder(),
onPressed: () {
_updateMenu(menuData.iconData);
menuAnimation.status == AnimationStatus.completed
? menuAnimation.reverse()
: menuAnimation.forward();
},
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Icon(
menuData.iconData,
color: Colors.white,
size: 45.0,
),
),
),
Transform.scale(
scale: menuAnimation.value,
child: Opacity(
opacity: menuAnimation.value,
child: Text(menuData.text),
),
),
],
);
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Flow(
delegate: FlowMenuDelegate(menuAnimation: menuAnimation),
children: menuItems
.map<Widget>((MenuData menuData) => flowMenuItem(menuData))
.toList(),
),
),
],
);
}
}
FlowMenuDelegate - for repaint childrens(menu)
class FlowMenuDelegate extends FlowDelegate {
FlowMenuDelegate({this.menuAnimation}) : super(repaint: menuAnimation);
final Animation<double> menuAnimation;
#override
bool shouldRepaint(FlowMenuDelegate oldDelegate) {
return menuAnimation != oldDelegate.menuAnimation;
}
#override
void paintChildren(FlowPaintingContext context) {
double dx = 0.0, dy = 0.0;
for (int i = 0; i < context.childCount; ++i) {
// dx = context.getChildSize(i).width * i;
dx = 200.0 * cos(menuItems[i].angle * (pi / 180));
dy = 200.0 * sin(menuItems[i].angle * (pi / 180));
context.paintChild(
i,
transform: Matrix4.translationValues(
dx * menuAnimation.value,
dy * menuAnimation.value,
0,
),
);
}
}
}
Test Data
final List<MenuData> menuItems = <MenuData>[
MenuData(iconData: Icons.home, text: "Home", angle: -60),
MenuData(iconData: Icons.new_releases, text: "Release", angle: -30),
MenuData(iconData: Icons.notifications, text: "Notification", angle: 0),
MenuData(iconData: Icons.settings, text: "Settings", angle: 30),
MenuData(iconData: Icons.menu, text: "Menu", angle: 60),
];

Flutter sliding container into another container to show or hide some icons like with toolbar

in container you suppose i have AppBar() witch that i want to have another invisible container, like with this screen shot:
in that two other container are invisible and i want to show them by sliding from top to bottom or bottom to top for change visibility on visible or invisible
sliding from top to bottom to show or sliding that to top to hide
sliding from bottom to top to show or sliding that to bottom to hide
is any library to implementing this sliding animation?
Click on arrows to bring the top/bottom containers, and after that to hide those new containers, you can either drag them up/down or simply touch them.
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
static double _height = 100, _one = -_height, _two = _height;
final double _oneFixed = -_height;
final double _twoFixed = _height;
Duration _duration = Duration(milliseconds: 5);
bool _top = false, _bottom = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Slide")),
body: SizedBox(
height: _height,
child: Stack(
children: <Widget>[
Positioned(
left: 0,
right: 0,
height: _height,
child: GestureDetector(
onVerticalDragEnd: (details) {
if (details.velocity.pixelsPerSecond.dy >= 0) _toggleTop();
else _toggleBottom();
},
child: _myContainer(
color: Colors.yellow[800],
text: "Old Container",
child1: IconButton(
icon: Icon(Icons.arrow_downward),
onPressed: _toggleTop,
),
child2: IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: _toggleBottom,
),
),
),
),
Positioned(
left: 0,
right: 0,
top: _one,
height: _height,
child: GestureDetector(
onTap: _toggleTop,
onPanEnd: (details) => _toggleTop(),
onPanUpdate: (details) {
_one += details.delta.dy;
if (_one >= 0) _one = 0;
if (_one <= _oneFixed) _one = _oneFixed;
setState(() {});
},
child: _myContainer(
color: _one >= _oneFixed + 1 ? Colors.red[800] : Colors.transparent,
text: "Upper Container",
),
),
),
Positioned(
left: 0,
right: 0,
top: _two,
height: _height,
child: GestureDetector(
onTap: _toggleBottom,
onPanEnd: (details) => _toggleBottom(),
onPanUpdate: (details) {
_two += details.delta.dy;
if (_two <= 0) _two = 0;
if (_two >= _twoFixed) _two = _twoFixed;
setState(() {});
},
child: _myContainer(
color: _two <= _twoFixed - 1 ? Colors.green[800] : Colors.transparent,
text: "Bottom Container",
),
),
),
],
),
),
);
}
void _toggleTop() {
_top = !_top;
Timer.periodic(_duration, (timer) {
if (_top) _one += 2;
else _one -= 2;
if (_one >= 0) {
_one = 0;
timer.cancel();
}
if (_one <= _oneFixed) {
_one = _oneFixed;
timer.cancel();
}
setState(() {});
});
}
void _toggleBottom() {
_bottom = !_bottom;
Timer.periodic(_duration, (timer) {
if (_bottom) _two -= 2;
else _two += 2;
if (_two <= 0) {
_two = 0;
timer.cancel();
}
if (_two >= _twoFixed) {
_two = _twoFixed;
timer.cancel();
}
setState(() {});
});
}
Widget _myContainer({Color color, String text, Widget child1, Widget child2, Function onTap}) {
Widget child;
if (child1 == null || child2 == null) {
child = Text(text, style: TextStyle(fontSize: 32, color: Colors.white, fontWeight: FontWeight.bold));
} else {
child = Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
child1,
child2,
],
);
}
return GestureDetector(
onTap: onTap,
child: Container(
color: color,
alignment: Alignment.center,
child: child,
),
);
}
}
Output:
If I got you correctly, this is the solution.
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
static double _height = 100, _offset = 10, _one = -(_height - _offset), _two = (_height - _offset);
final double _oneFixed = -(_height - _offset);
final double _twoFixed = (_height - _offset);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Testing")),
body: SizedBox(
height: _height,
child: Stack(
children: <Widget>[
Positioned(
left: 0,
right: 0,
height: _height,
child: _myContainer(color: Colors.grey[800], text: "Old Container"),
),
Positioned(
left: 0,
right: 0,
top: _one,
height: _height,
child: GestureDetector(
onPanUpdate: (details) {
_one += details.delta.dy;
if (_one >= 0) _one = 0;
if (_one <= _oneFixed) _one = _oneFixed;
setState(() {});
},
child: _myContainer(color: _one >= _oneFixed + 1 ? Colors.red[800] : Colors.transparent, text: "Upper Container"),
),
),
Positioned(
left: 0,
right: 0,
top: _two,
height: _height,
child: GestureDetector(
onPanUpdate: (details) {
_two += details.delta.dy;
if (_two <= 0) _two = 0;
if (_two >= _twoFixed) _two = _twoFixed;
setState(() {});
},
child: _myContainer(color: _two <= _twoFixed - 1 ? Colors.green[800] : Colors.transparent, text: "Bottom Container"),
),
),
],
),
),
);
}
Widget _myContainer({Color color, String text}) {
return Container(
color: color,
alignment: Alignment.center,
child: Text(text, style: TextStyle(fontSize: 32, color: Colors.white, fontWeight: FontWeight.bold)),
);
}
}