How to add videos in listview - flutter

I want to show images and videos in listview i am able show images but i want to show video also please help me . I want to create app like instagram here is my code for the video.
class mydynamic extends StatefulWidget {
#override
_mydynamicState createState() => _mydynamicState();
}
class _mydynamicState extends State<mydynamic> {
List<String> urls = [
"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4",
"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4",
"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"
];
VideoPlayerController _controller;
#override
void initState() {
super.initState();
_ controller = VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4')
..initialize().then((_) {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(title: Text("Adas")),
body: Center(
child: _controller.value.initialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: Container(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
}
I have tried this above example which is working fine but i am not able to apply the logic for putting the videos in listview please any solution for this. Thank you

Use ListView.Builder with List<VideoPlayerController> of video controllers
class _mydynamicState extends State<mydynamic> {
List<String> urls = [
"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4",
"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4",
"https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4"
];
List<VideoPlayerController> _controllers = [];
#override
void initState() {
super.initState();
urls.forEach((element) {
_controllers.add(VideoPlayerController.network(element));
});
}
void _playVideos() {
_controllers.forEach((controller) {
controller
..initialize().then((_) {
setState(() {});
});
controller.value.isPlaying ? controller.pause() : controller.play();
});
}
bool isVideosPlaying() {
for (VideoPlayerController controller in _controllers) {
if (controller.value.isPlaying) {
return true;
}
}
return false;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(title: Text("Adas")),
body: ListView.builder(
shrinkWrap: true,
itemBuilder: (ctx, index) {
VideoPlayerController controller = _controllers[index];
print(controller.value.isPlaying);
return Container(
child: controller.value.initialized
? AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: VideoPlayer(controller),
)
: Container(),
);
},
itemCount: urls.length,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_playVideos();
});
},
child: Icon(
isVideosPlaying() ? Icons.pause : Icons.play_arrow,
),
),
);
}
#override
void dispose() {
super.dispose();
_controllers.forEach((controller) {
controller.dispose();
});
}
}

Related

Pagination scroll top in flutter

I'm currently create chat in flutter and get the last messages , I want to handle when scrolling to top to load more messages how can I create that ?
If you want to implement swipe to refresh kind of behaviour, you can use RefreshIndicator. See the example and usage in this YouTube video.
All you have to do is wrap your scrollable widget (it can be ListView or SingleChildScrollView) in a RefreshIndicator and provide onRefresh method:
class PullToRefresh extends StatelessWidget {
const PullToRefresh({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: _refreshData,
child: ListView.builder( // or SingleChildScrollView
...
),
);
}
Future<void> _refreshData() async {
// load more items
}
}
ListView reverse: true displays the List from the bottom to the top.
and this is how to implement pagination
class HomeState extends State<Home> {
ScrollController? controller;
final _all = <WordPair>[];
final _saved = Set<WordPair>();
final _biggerFont = const TextStyle(fontSize: 18.0);
GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
bool isLoading = false;
#override
void initState() {
super.initState();
_all.addAll(generateWordPairs().take(20));
controller = ScrollController()..addListener(_scrollListener);
}
#override
void dispose() {
super.dispose();
controller?.dispose();
}
void _scrollListener() {
if (controller!.position.pixels == controller!.position.maxScrollExtent) {
startLoader();
}
}
void startLoader() {
setState(() {
isLoading = !isLoading;
fetchData();
});
}
fetchData() async {
var _duration = const Duration(seconds: 2);
return Timer(_duration, onResponse);
}
void onResponse() {
setState(() {
isLoading = !isLoading;
_all.addAll(generateWordPairs().take(20));
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
title: const Text(
"List load more example",
style: TextStyle(color: Colors.white),
),
),
body: Stack(
children: <Widget>[
_buildSuggestions(),
_loader(),
],
),
);
}
Widget _buildRow(WordPair pair) {
final alreadySaved = _saved.contains(pair);
return Column(
children: <Widget>[
ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: Icon(
alreadySaved ? Icons.check : Icons.check,
color: alreadySaved ? Colors.deepOrange : null,
),
onTap: () {
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
),
const Divider(),
],
);
}
Widget _buildSuggestions() {
return ListView.builder(
reverse: true,
padding: const EdgeInsets.all(16.0),
controller: controller,
itemCount: _all.length,
itemBuilder: (context, i) {
return _buildRow(_all[i]);
});
}
Widget _loader() {
return isLoading
? const Align(
child: SizedBox(
width: 70.0,
height: 70.0,
child: Padding(
padding: EdgeInsets.all(5.0),
child: Center(child: CircularProgressIndicator())),
),
alignment: FractionalOffset.topCenter,
)
: const SizedBox(
width: 0.0,
height: 0.0,
);
}
}
You can get full code from Github HERE

Flutter: Having a problem with Custom Drawer and internal navigation on fab pressed

I am trying to build a custom drawer, just to practice while I study flutter and collecting ideas from videos I see on the web.
In the app I am trying to make, I use Provider and Navigator 2.0 (Router) and it has been not easy so far to implement Navigator 2.
The as mentioned is made as a Stack that has as children the DrawerComponent and the Specific page handled by a DrawerManager and an AppRouter.
In the main page I have a Floating Action Button that on pressed does an effect transitioning from the list of Todos to the AddTodo Screen like a circle from the bottom corner revealing the new page.
like this image shows
The problem is basically that whenever I press the FAB the animation works, but I do not want to see the Drawer in full page like that is the page from where I am transitioning. Instead I would like to see a transition from the TodoList page to the AddTodo Page.
Here the code:
class _MainPageState extends State<MainPage> {
final _drawerManager = DrawerManager();
late AppRouter _appRouter;
#override
void initState() {
super.initState();
_appRouter = AppRouter(drawerManager: _drawerManager);
}
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => _drawerManager),
Provider<ITodoRepository>(
lazy: false,
create: (_) =>
TodoRepository(db: Provider.of<HeyTaskDatabase>(context)),
)
],
child: Consumer<DrawerManager>(
builder: (context, drawerManager, child) {
return MaterialApp(
home: Scaffold(
backgroundColor: const Color.fromARGB(255, 2, 9, 38),
body: Stack(children: [
const DrawerComponent(),
WillPopScope(
onWillPop: () async {
if (drawerManager.isDrawerOpen) {
drawerManager.closeDrawer();
return false;
} else {
return true;
}
},
child: GestureDetector(
onTap: () {
drawerManager.closeDrawer();
},
onHorizontalDragStart: (details) =>
drawerManager.setDragging(true),
onHorizontalDragUpdate: (details) {
if (!drawerManager.isDragging) return;
const minMove = 1;
if (details.delta.dx > minMove) {
drawerManager.openDrawer();
} else if (details.delta.dx < -minMove) {
drawerManager.closeDrawer();
}
drawerManager.setDragging(false);
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 250),
transform: Matrix4.translationValues(
drawerManager.xOffSet, drawerManager.yOffSet, 0)
..scale(drawerManager.scaleFactor),
child: AbsorbPointer(
absorbing: drawerManager.isDrawerOpen,
child: ClipRRect(
borderRadius: BorderRadius.circular(
drawerManager.isDrawerOpen ? 20 : 0),
child: Router(
routerDelegate: _appRouter,
backButtonDispatcher:
RootBackButtonDispatcher(),
),
),
)),
),
)
])));
},
),
);
}
}
Then the TodoScreen:
class _TodoRoosterScreenState extends State<TodoRoosterScreen> {
#override
Widget build(BuildContext context) => Consumer<DrawerManager>(
builder: (context, drawerManager, child) {
return Scaffold(
backgroundColor: LightColors.backgroundColor,
appBar: AppBar(
elevation: 0.0,
backgroundColor: LightColors.backgroundColor,
leading: DrawerMenuComponent(
onClick: () {
Provider.of<DrawerManager>(context, listen: false)
.openDrawer();
},
),
actions: <Widget>[
IconButton(
onPressed: () {},
icon: const Icon(Icons.search),
color: Colors.black38,
)
],
title: const Text(""),
),
body: _buildTodoList(context),
floatingActionButton: FloatingActionButton(
backgroundColor: LightColors.iconBlue,
onPressed: () async {
Provider.of<DrawerManager>(context, listen: false).goTo(AvailablePages.addTodo);
},
child: const Icon(Icons.add),
),
);
},
);
Widget _buildTodoList(BuildContext context) {
return StreamBuilder<List<Todo>>(
stream: Provider.of<ITodoRepository>(context, listen: false).watchTodos(),
builder: (context, AsyncSnapshot<List<Todo>> snapshot) {
if (snapshot.hasData) {
final todos = snapshot.data ?? [];
return ListView.builder(
itemCount: todos.length,
itemBuilder: (BuildContext context, int index) {
final todo = todos[index];
return Padding(
padding: const EdgeInsets.only(right: 16.0, left: 16.0),
child: SizedBox(
height: 70,
child: _buildSlidable(context, todo),
),
);
},
);
} else if(snapshot.hasError) {
return Text('${snapshot.error}');
}
return const Center(child: CircularProgressIndicator(),);
}
);
}
-----
And the add todo one:
class AddTodoScreen extends StatefulWidget {
const AddTodoScreen({Key? key}) : super(key: key);
static MaterialPage page() {
return MaterialPage(
name: HeyTaskPages.addTodoPath,
key: ValueKey(HeyTaskPages.addTodoPath),
child: const AddTodoScreen());
}
#override
_AddTodoScreenState createState() => _AddTodoScreenState();
}
class _AddTodoScreenState extends State<AddTodoScreen> with SingleTickerProviderStateMixin {
late AnimationController _controller;
#override
void initState() {
super.initState();
_controller =
AnimationController(
vsync: this,
duration: const Duration(milliseconds: 400),
upperBound:1.3);
_controller.forward();
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child){
return ClipPath(
clipper:AddTaskClipper(value: _controller.value),
child:child ,
);
},
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text("Add Todo Screen"),
],
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: LightColors.iconBlue,
onPressed: () async {
//Provider.of<ITodoRepository>(context, listen: false).insertTodo(todo)
_controller.reverse().then((value) => Provider.of<DrawerManager>(context, listen: false).goTo(AvailablePages.todoRooster));
},
child: const Icon(Icons.done),
)
),
);
}
}
class AddTaskClipper extends CustomClipper<Path> {
final double value;
AddTaskClipper({required this.value});
#override
Path getClip(Size size) {
var path = Path();
path.addOval(Rect.fromCircle(center: Offset(size.width, size.height), radius: value *size.height));
path.close();
return path;
}
#override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => true;
}
The APPRouter
class AppRouter extends RouterDelegate
with ChangeNotifier, PopNavigatorRouterDelegateMixin {
#override
final GlobalKey<NavigatorState> navigatorKey;
final DrawerManager drawerManager;
AppRouter({
required this.drawerManager,
}) : navigatorKey = GlobalKey<NavigatorState>() {
drawerManager.addListener(notifyListeners);
}
#override
void dispose() {
drawerManager.addListener(notifyListeners);
super.dispose();
}
// 5
#override
Widget build(BuildContext context) {
return Navigator(
transitionDelegate: NoAnimationTransitionDelegate(),
key: navigatorKey,
onPopPage: _handlePopPage,
pages: [
if(drawerManager.selectedPage == AvailablePages.todoRooster) TodoRoosterScreen.page(openDrawer: drawerManager.openDrawer),
if(drawerManager.selectedPage == AvailablePages.categories) CategoriesScreen.page(openDrawer: drawerManager.openDrawer),
if(drawerManager.selectedPage == AvailablePages.settings) SettingsScreen.page(openDrawer: drawerManager.openDrawer),
if(drawerManager.selectedPage == AvailablePages.addTodo) AddTodoScreen.page(),
],
);
}
The drawer manager:
class DrawerManager extends ChangeNotifier{
AvailablePages selectedPage = AvailablePages.todoRooster;
void goTo(AvailablePages page){
if(selectedPage == page) {
closeDrawer();
return;
}
closeDrawer();
selectedPage = page;
}
double xOffSet = 0;
double yOffSet = 0;
double scaleFactor = 1;
bool isDrawerOpen = false;
bool isDragging = false;
void openDrawer() {
xOffSet = 230;
yOffSet = 100;
scaleFactor = 0.8;
isDrawerOpen = true;
notifyListeners();
}
void closeDrawer() {
xOffSet = 0;
yOffSet = 0;
scaleFactor = 1;
isDrawerOpen = false;
notifyListeners();
}
void setDragging(bool input) {
isDragging = input;
notifyListeners();
}
}
Could you give me a hand on How I could solve this or provide some snippets that could help? I tried many things and nothing I tried worked, and I know I am missing something.
Any help will be really appreciated, thank you all in advance!

Flutter: Videos not being played with proper aspect ratio

I am trying to play videos obtained from the web with its original aspect ratio. With the code I have the videos are returned with a stretched aspect ratio. I am not sure why this is. I have been doing research but cannot find a solution. How do I fix this?
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
class VideoTile1 extends StatefulWidget {
const VideoTile1({Key? key}) : super(key: key);
#override
_VideoTileState createState() => _VideoTileState();
}
class _VideoTileState extends State<VideoTile1> {
late VideoPlayerController _videoController;
late Future _intitializeVideoPlayer;
#override
void initState() {
_videoController = VideoPlayerController.network(
'https://res.cloudinary.com/nifty-gateway/video/upload/v1610827323/A/Billelis/%CE%A0%CE%91%CE%98%CE%9F%CE%A3_qyarem.mp4');
_intitializeVideoPlayer = _videoController.initialize();
_videoController.setLooping(true);
_videoController.play();
super.initState();
}
#override
void dispose() {
_videoController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: _intitializeVideoPlayer,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return VideoPlayer(_videoController);
} else {
return Container(color: Colors.grey[800]);
}
},
),
);
}
}
You can try using AspectRatio Widget with aspectRatio: _videoController.value.aspectRatio,
VideoPlayer widget wrapper
https://api.flutter.dev/flutter/widgets/AspectRatio-class.html
I am also new to flutter, here is my way to use and play/pause video , i hope can help you.
return _videoPlayerController.value.isInitialized
? Center(
child: GestureDetector(
onTap: () {
setState(() {
_videoPlayerController.value.isPlaying
? _videoPlayerController.pause()
: _videoPlayerController.play();
});
},
child: AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: Stack(
children: [
VideoPlayer(
_videoPlayerController,
),
_videoPlayerController.value.isPlaying
? Container()
: Center(
child: Icon(
Icons.play_arrow,
size: 80,
color: Colors.white.withOpacity(0.4),
),
)
],
),
),
),
)
: const CircularProgressIndicator();

AnimatedCrossFade State not Changing

I am unable to get a basic implementation of AnimatedCrossFade working. I am able to change the state successfully but the animation does not trigger when the state is changed. Here is what I have:
class Home extends StatefulWidget {
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
bool showPost;
#override
void initState() {
showPost = true;
super.initState();
}
#override
Widget build(BuildContext context) {
return CupertinoTabView(builder: (context) {
return getPage();
});
}
Widget getPage() {
return Center(
child: Row(children: [
CupertinoButton(
child: Text("press"),
onPressed: () {
setState(() {
showPost = !showPost;
});
log(showPost.toString());
},
),
AnimatedCrossFade(
duration: const Duration(seconds: 3),
firstChild: Center(child: Text("First Option")),
secondChild: Center(
child: Text("Second Option")),
crossFadeState:
showPost ? CrossFadeState.showFirst : CrossFadeState.showSecond)
]));
}
}

How to make a text become clickable after 30 secs in flutter?

I am making a login app where by i have created an OTP validation page. In this page i want to make a resend option which is clickable only after 30 seconds of page loading and once clicked becomes unclickable for ever.
I am new to flutter so I am sorry if this seems trivial.
You can follow this code.
class TestButton extends StatefulWidget {
#override
_TestButtonState createState() => _TestButtonState();
}
class _TestButtonState extends State<TestButton> {
bool firstStateEnabled = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
Timer(Duration(milliseconds: 30000), () {
setState(() {
firstStateEnabled = true;
});
});
return Scaffold(
body: Container(
child: firstStateEnabled
? Center(
child: Container(
width: 200,
height: 55,
child: RaisedButton(
onPressed: () {},
child: Text("Resend OTP"),
),
),
)
: Center(child: Container()),
),
);
}
}
Or if you need only one time the button than you can follow below codes.
Install timer_count_down.
Then, below code.
class TestButton extends StatefulWidget {
#override
_TestButtonState createState() => _TestButtonState();
}
class _TestButtonState extends State<TestButton> {
bool firstStateEnabled = false;
final CountdownController controller = CountdownController();
final int seconds = 30;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
child: firstStateEnabled
? Center(
child: Container(
width: (200),
height: 55,
child: RaisedButton(
onPressed: () {
setState(() {
firstStateEnabled = false;
});
},
child: Text("Resend OTP"),
),
),
)
: Center(child: Container()),
),
Countdown(
controller: controller,
seconds: seconds,
build: (context, double time) {
return Container();
},
interval: Duration(milliseconds: 100),
onFinished: () {
setState(() {
firstStateEnabled = true;
;
});
},
)
],
),
);
}
}