1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; void main() { runApp( ChangeNotifierProvider<AnimationData>( create: (context) => AnimationData(), builder: (context, child) => const MyApp(), ), ); } class AnimationData extends ChangeNotifier { double _percentage = 0.0; bool _isAnimationRunning = false; double get percentage => _percentage; bool get isAnimationRunning => _isAnimationRunning; set percentage(double value) { _percentage = value; notifyListeners(); } void startAnimation() { if (_isAnimationRunning) return; _isAnimationRunning = true; Timer.periodic(const Duration(milliseconds: 30), (timer) { if (_percentage < 1.0) { _percentage += 0.01; notifyListeners(); } else { timer.cancel(); _isAnimationRunning = false; } }); } void resetAnimation() { _percentage = 0.0; notifyListeners(); } } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Fluid Fill Animation', theme: ThemeData(primarySwatch: Colors.blue), home: const MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of<AnimationData>(context, listen: false).startAnimation(); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Fluid Fill Animation')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const FluidCircle(), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () { Provider.of<AnimationData>( context, listen: false, ).startAnimation(); }, child: const Text('Start Animation'), ), const SizedBox(width: 20), ElevatedButton( onPressed: () { Provider.of<AnimationData>( context, listen: false, ).resetAnimation(); }, child: const Text('Reset Animation'), ), ], ), ], ), ), ); } } class FluidCircle extends StatelessWidget { const FluidCircle({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final animationData = Provider.of<AnimationData>(context); return CustomPaint( painter: FluidPainter(animationData.percentage), size: const Size(200, 200), ); } } class FluidPainter extends CustomPainter { final double percentage; FluidPainter(this.percentage); @override void paint(Canvas canvas, Size size) { final center = size.center(Offset.zero); final radius = size.width / 2; // Define the wave parameters final waveAmplitude = radius / 20; final waveFrequency = 5.0; // Calculate the current water level final waterLevel = radius - (radius * 2 * percentage); // Create the path for the filled portion with wave effect final filledPath = Path(); // Move to the starting point on the left, start from above the circle to avoid unfilled area filledPath.moveTo(0, center.dy + waterLevel - waveAmplitude); // Draw the wave for (double x = 0; x <= size.width; x += 1) { final y = center.dy + waterLevel + waveAmplitude * sin(waveFrequency * (x / radius) + percentage * 2 * pi); filledPath.lineTo(x, y); } // Complete the path to close the filled area filledPath.lineTo(size.width, size.height); filledPath.lineTo(0, size.height); filledPath.close(); // Clip the path to the circle canvas.clipPath( Path()..addOval(Rect.fromCircle(center: center, radius: radius)), ); // Draw the filled portion final filledPaint = Paint()..color = Colors.blue; canvas.drawPath(filledPath, filledPaint); // Draw the circle outline final circlePaint = Paint() ..color = Colors.blue ..style = PaintingStyle.stroke ..strokeWidth = 4; canvas.drawCircle(center, radius, circlePaint); // Draw the percentage text final textPainter = TextPainter( text: TextSpan( text: '${(percentage * 100).toStringAsFixed(0)}%', style: TextStyle( color: (percentage * 100) > 50 ? Colors.white : Colors.grey, fontSize: 24, ), ), textDirection: TextDirection.ltr, textAlign: TextAlign.center, ); textPainter.layout(minWidth: size.width, maxWidth: size.width); textPainter.paint( canvas, center - Offset(textPainter.width / 2, textPainter.height / 2), ); } @override bool shouldRepaint(covariant FluidPainter oldDelegate) { return oldDelegate.percentage != percentage; } } |
Android App Development for Phones/Tablets
Its all about , Latest Android App Development for Phones/Tablets, showing Step by step development Tutorials for beginners, Professionals android developers,Best Practices, Latest android code patterns, UI design Patterns
Monday, 16 June 2025
Flutter Fluid Fill Animation code
Thursday, 14 November 2024
Flutter UI - Profile Page
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart'; import 'TCustomCurvedEdges.dart'; class ProfileScreen2 extends StatefulWidget { const ProfileScreen2({super.key}); @override State<ProfileScreen2> createState() => _ProfileScreen2State(); } class _ProfileScreen2State extends State<ProfileScreen2> { @override Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( child: Column( children: [ ClipPath( clipper: TCustomCurvedEdges(), child: Container( // color: const Color.fromARGB(255, 75, 104, 255), color: Colors.red[300], padding: const EdgeInsets.all(0), child: SizedBox( height: 300, child: Stack( children: [ // 3 LEFT side curves Positioned( top: 0, left: -210, child: Container( width: 300, height: 300, decoration: BoxDecoration( borderRadius: BorderRadius.circular(300), color: Colors.white.withOpacity(0.1))), ), Positioned( top: 0, left: -240, child: Container( width: 300, height: 300, decoration: BoxDecoration( borderRadius: BorderRadius.circular(300), color: Colors.white.withOpacity(.1))), ), Positioned( top: 0, left: -270, child: Container( width: 300, height: 300, decoration: BoxDecoration( borderRadius: BorderRadius.circular(300), color: Colors.white.withOpacity(.1))), ), // 3 RIGHT side curves Positioned( top: 0, right: -210, child: Container( width: 300, height: 300, decoration: BoxDecoration( borderRadius: BorderRadius.circular(300), color: Colors.white.withOpacity(0.1))), ), Positioned( top: 0, right: -240, child: Container( width: 300, height: 300, decoration: BoxDecoration( borderRadius: BorderRadius.circular(300), color: Colors.white.withOpacity(.1))), ), Positioned( top: 0, right: -270, child: Container( width: 300, height: 300, decoration: BoxDecoration( borderRadius: BorderRadius.circular(300), color: Colors.white.withOpacity(.1))), ), // Bottom Curve - try with -10, -150 // Positioned( // bottom: -150, // child: Container( // width: MediaQuery.of(context).size.width, // height: 300, // decoration: BoxDecoration( // borderRadius: BorderRadius.circular(300), // color: Colors.white.withOpacity(.2))), // ), // Circle Avatar Container( width: double.infinity, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: const [ CircleAvatar( radius: 60, backgroundImage: NetworkImage( "https://randomuser.me/api/portraits/men/46.jpg")), SizedBox( height: 10, ), Text( "Pratap Kumar", style: TextStyle( color: Colors.white, fontWeight: FontWeight.w600, fontSize: 17), ) ], ), ), ], )), ), ), Column( children: [ ListTile( leading: Icon(Icons.person_4), title: Text("Profile"), trailing: Icon( Icons.arrow_forward_ios, size: 14, ), onTap: () { print("Profile"); }, ), ListTile( leading: Icon(Icons.security), title: Text("Change Password"), trailing: Icon( Icons.arrow_forward_ios, size: 14, ), onTap: () { print("Change Password"); }, ), ListTile( leading: Icon(Icons.lock), title: Text("Privacy Policy"), trailing: Icon( Icons.arrow_forward_ios, size: 14, ), onTap: () { print("Privacy "); }, ), ListTile( leading: Icon(Icons.help_center), title: Text("Help Center"), trailing: Icon( Icons.arrow_forward_ios, size: 14, ), onTap: () { print("Help Center "); }, ), ListTile( leading: Icon(Icons.star), title: Text("Rate Us"), trailing: Icon( Icons.arrow_forward_ios, size: 14, ), onTap: () { print("Help Center "); }, ), ListTile( leading: Icon(Icons.settings), title: Text("Settings"), trailing: Icon( Icons.arrow_forward_ios, size: 14, ), onTap: () { print("Settings "); }, ), ListTile( leading: Icon(Icons.logout), title: Text( "Logout", style: TextStyle( fontWeight: FontWeight.w500, color: Colors.red, ), ), trailing: Icon( Icons.arrow_forward_ios, size: 14, ), onTap: () { print("Logout "); }, ), ], ) ], )), ); } }TCustomCurvedEdges.dart
========================
import 'package:flutter/material.dart';
class TCustomCurvedEdges extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, size.height);
final firstCurve = Offset(0, size.height - 20);
final lastCurve = Offset(30, size.height - 20);
path.quadraticBezierTo(
firstCurve.dx, firstCurve.dy, lastCurve.dx, lastCurve.dy);
final secondFirstCurve = Offset(0, size.height - 20);
final secondLastCurve = Offset(size.width - 30, size.height - 20);
path.quadraticBezierTo(secondFirstCurve.dx, secondFirstCurve.dy,
secondLastCurve.dx, secondLastCurve.dy);
final thirdFirstCurve = Offset(size.width, size.height - 20);
final thirdLastCurve = Offset(size.width, size.height);
path.quadraticBezierTo(thirdFirstCurve.dx, thirdFirstCurve.dy,
thirdLastCurve.dx, thirdLastCurve.dy);
path.lineTo(size.width, 0);
path.close();
return path;
}
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
return true;
}
}
Screenshot:
============
Tuesday, 12 November 2024
Flutter Bottom Navigation UI
CurvedBottomBarM3.dart
=======================
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_ui_screens/screens/bottombar/SampleTestScreen.dart'; class CurvedBottomBarM3 extends StatefulWidget { @override _CurvedBottomBarM3State createState() => _CurvedBottomBarM3State(); } class _CurvedBottomBarM3State extends State<CurvedBottomBarM3> { int _selectedIndex = 0; void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } _getBody() { switch (_selectedIndex) { case 0: return SampleTestPage("Home"); case 1: return SampleTestPage("Search"); case 2: return SampleTestPage("Cart"); case 3: return SampleTestPage("Wishlist"); case 4: return SampleTestPage("Profile"); default: return Container(color: Colors.red); } } Widget buildTabItem( {required IconData icon, required String label, required int index}) { final isSelected = _selectedIndex == index; return Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( height: 30, width: 30, child: IconButton( padding: const EdgeInsets.all(0), icon: Icon(icon), onPressed: () => _onItemTapped(index), color: isSelected ? Colors.red : Colors.grey, ), ), Text( label, style: TextStyle( fontSize: 11, color: isSelected ? Colors.red : Colors.grey, ), ), Container(height: 3), Container( decoration: BoxDecoration( color: index == _selectedIndex ? Colors.red : Colors.transparent, shape: BoxShape.circle, ), height: 5, width: 5, ), ], ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( elevation: 2, title: const Text("Custom Bottom Navigation"), ), body: _getBody(), bottomNavigationBar: BottomAppBar( shape: const CircularNotchedRectangle(), color: Colors.white, notchMargin: 8, // Increased notch margin child: Padding( padding: const EdgeInsets.symmetric(horizontal: 15.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ buildTabItem(icon: CupertinoIcons.home, label: "Home", index: 0), buildTabItem( icon: CupertinoIcons.search, label: "Search", index: 1), SizedBox(width: 40), // Spacing for the floating button buildTabItem( icon: CupertinoIcons.heart, label: "Wishlist", index: 2), buildTabItem( icon: CupertinoIcons.settings, label: "Settings", index: 3), ], ), ), ), floatingActionButtonLocation: FloatingActionButtonLocation .centerDocked, // Changed from centerDocked to centerFloat floatingActionButton: Stack( alignment: Alignment.center, children: [ // Custom shadow using a Container Container( width: 60, height: 60, decoration: BoxDecoration( shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.red.withOpacity(0.3), // Shadow color spreadRadius: 8, blurRadius: 15, ), ], ), ), // FloatingActionButton on top FloatingActionButton( shape: CircleBorder(), onPressed: () { // Action for the FAB }, child: Icon( Icons.shopping_basket, color: Colors.white, ), backgroundColor: Colors.red, elevation: 0, // Set to 0 to avoid default shadow ), ], ), ); } }
SampleTestPage.dart
====================
import 'package:flutter/material.dart';
class SampleTestPage extends StatefulWidget {
String pageTitle;
SampleTestPage(this.pageTitle, {super.key});
@override
State<SampleTestPage> createState() => _SampleTestPageState();
}
class _SampleTestPageState extends State<SampleTestPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Text(
widget.pageTitle,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w300),
)),
),
);
}
}
Customise bottom bar tab item selection based on requirement using this buildTabItem code
=============
Screenshots
=============
Subscribe to:
Posts (Atom)