Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/SplashByte/widget_loading i…
Browse files Browse the repository at this point in the history
…nto main
  • Loading branch information
maeddin committed Mar 4, 2021
2 parents 1b33e58 + ebabb2d commit 390988b
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 186 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
[![pub points](https://badges.bar/widget_loading/pub%20points)](https://pub.dev/packages/widget_loading/score)
<a href="https://github.com/SplashByte/widget_loading/blob/main/LICENSE"><img src="https://img.shields.io/github/license/SplashByte/widget_loading.svg" alt="license"></a>

A simple widget for loading widget contents.
### If you like this package, please leave a like there on [pub.dev](https://pub.dev/packages/widget_loading) and star on [GitHub](https://github.com/SplashByte/widget_loading).

Simple widgets for loading widget contents.
It's an easy way to hide a widget when you have nothing to show and need a loading animation at the same time.

![example1](https://user-images.githubusercontent.com/43761463/109703122-66cd3480-7b95-11eb-9862-dfb45ed96b49.gif)
Expand Down
57 changes: 31 additions & 26 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ class _ExampleState extends State<Example> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Example'),),
appBar: AppBar(
title: Text('Example'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
Expand All @@ -92,13 +94,14 @@ class _ExampleState extends State<Example> {
height: height,
decoration: BoxDecoration(color: Colors.purple, borderRadius: BorderRadius.circular(5.0))),
wiperWidth: 50),
counterCard(Curves.linear,
builder: (width, height) => Container(
width: width,
height: height,
decoration: BoxDecoration(color: Colors.purple, borderRadius: BorderRadius.circular(5.0))),
wiperWidth: 10,
deformingFactor: 0.2,
counterCard(
Curves.linear,
builder: (width, height) => Container(
width: width,
height: height,
decoration: BoxDecoration(color: Colors.purple, borderRadius: BorderRadius.circular(5.0))),
wiperWidth: 10,
deformingFactor: 0.2,
direction: WiperDirection.up,
),
counterCard(Curves.easeInOutCirc, padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 30.0)),
Expand All @@ -114,7 +117,8 @@ class _ExampleState extends State<Example> {
width: width,
height: height,
decoration: BoxDecoration(color: Colors.purple, borderRadius: BorderRadius.circular(5.0))),
wiperWidth: 20, direction: WiperDirection.left),
wiperWidth: 20,
direction: WiperDirection.left),
counterCardCircle(Curves.linear),
],
),
Expand All @@ -128,7 +132,8 @@ class _ExampleState extends State<Example> {
{WiperBuilder? builder,
double wiperWidth = 15,
double deformingFactor = 0.5,
WiperDirection direction = WiperDirection.right, EdgeInsetsGeometry padding = const EdgeInsets.all(15.0)}) =>
WiperDirection direction = WiperDirection.right,
EdgeInsetsGeometry padding = const EdgeInsets.all(15.0)}) =>
Card(
elevation: 5.0,
child: Padding(
Expand Down Expand Up @@ -158,30 +163,29 @@ class _ExampleState extends State<Example> {
);

Widget counterCardCircle(Curve curve, {WiperBuilder? builder}) => InkWell(
onTap: ()=>Navigator.of(context).push(MaterialPageRoute(builder: (c)=>LoadingScaffold())),
child: Card(
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (c) => LoadingScaffold())),
child: Card(
elevation: 5.0,
child: CircularWidgetLoading(
dotColor: Colors.red,
dotCount: 10,
rollingFactor: 0.8,
loading: loading,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 50.0),
child: ListTile(
leading: Text(
'Counter',
style: Theme.of(context).textTheme.headline5,
),
trailing: Text(
'$counter',
style: Theme.of(context).textTheme.headline5,
),
)
),
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 50.0),
child: ListTile(
leading: Text(
'Counter',
style: Theme.of(context).textTheme.headline5,
),
trailing: Text(
'$counter',
style: Theme.of(context).textTheme.headline5,
),
)),
),
),
);
);
}

class LoadingScaffold extends StatefulWidget {
Expand Down Expand Up @@ -214,7 +218,8 @@ class _LoadingScaffoldState extends State<LoadingScaffold> {

@override
Widget build(BuildContext context) {
return Material(child: CircularWidgetLoading(
return Material(
child: CircularWidgetLoading(
padding: EdgeInsets.zero,
child: Scaffold(
appBar: AppBar(title: Text('Example')),
Expand Down
4 changes: 2 additions & 2 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.2.0"
version: "0.2.0-nullsafety.0"
sdks:
dart: ">=2.12.0-259.16.beta <3.0.0"
dart: ">=2.12.0 <3.0.0"
flutter: ">=1.17.0"
16 changes: 8 additions & 8 deletions lib/src/utils/extensions.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import 'dart:math';
import 'package:flutter/animation.dart';

extension Derivation on CurvedAnimation{
extension Derivation on CurvedAnimation {
/// Returns the current speed/derivation of the Curve.
///
/// Does not handle the case that [parent.value] is not between 0.0 and 1.0.
double get speed{
double get speed {
double dif = 0.01;
switch (this.status){
switch (this.status) {
case AnimationStatus.forward:
double value = max(this.parent.value - dif, 0.0);
if(value == this.parent.value) return 0.0;
return (this.value - this.curve.transform(value))/(this.parent.value-value);
if (value == this.parent.value) return 0.0;
return (this.value - this.curve.transform(value)) / (this.parent.value - value);
case AnimationStatus.reverse:
double value = min(this.parent.value + dif, 1.0);
if(value == this.parent.value) return 0.0;
return (this.value - this.curve.transform(value))/(value-this.parent.value);
if (value == this.parent.value) return 0.0;
return (this.value - this.curve.transform(value)) / (value - this.parent.value);
case AnimationStatus.dismissed:
case AnimationStatus.completed:
break;
}

return 0.0;
}
}
}
2 changes: 1 addition & 1 deletion lib/src/utils/loading_state.dart
Original file line number Diff line number Diff line change
@@ -1 +1 @@
enum LoadingState { APPEARING, DISAPPEARING, LOADED, LOADING }
enum LoadingState { APPEARING, DISAPPEARING, LOADED, LOADING }
104 changes: 8 additions & 96 deletions lib/src/widgets/circular_widget_loading.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:widget_loading/src/utils/loading_state.dart';
import 'package:widget_loading/src/widgets/loading_widget.dart';
import 'package:widget_loading/src/widgets/wiper_loading.dart';
import 'package:widget_loading/src/widgets/widget_sized_box.dart';

typedef DotBuilder = Widget Function(double radius);

Expand Down Expand Up @@ -91,7 +91,8 @@ class CircularWidgetLoading extends StatefulWidget {
_CircularWidgetLoadingState createState() => _CircularWidgetLoadingState();
}

class _CircularWidgetLoadingState extends State<CircularWidgetLoading> with TickerProviderStateMixin, LoadingWidget {
class _CircularWidgetLoadingState extends State<CircularWidgetLoading>
with TickerProviderStateMixin, LoadingWidgetState {
late AnimationController _controller;
late AnimationController _appearingController;
late Animation<double> _appearingAnimation;
Expand Down Expand Up @@ -212,7 +213,7 @@ class _CircularWidgetLoadingState extends State<CircularWidgetLoading> with Tick
Widget loadedChild = animatedSizeWidget(_childKey);
ThemeData theme = Theme.of(context);
Color dotColor = widget.dotColor ?? theme.accentColor;
TextDirection textDirection = Directionality.maybeOf(context)??TextDirection.ltr;
TextDirection textDirection = Directionality.maybeOf(context) ?? TextDirection.ltr;

Widget stack = Stack(
children: [
Expand All @@ -224,7 +225,7 @@ class _CircularWidgetLoadingState extends State<CircularWidgetLoading> with Tick
loadedChild
else if (appearing || disappearing)
ClipOval(
clipper: DotClipper(
clipper: _DotClipper(
_appearingAnimation.value, widget.dotRadius, widget.maxLoadingCircleSize, widget.loadingCirclePadding),
child: Stack(children: [
Container(
Expand Down Expand Up @@ -262,64 +263,6 @@ class _CircularWidgetLoadingState extends State<CircularWidgetLoading> with Tick
],
);
return Directionality(textDirection: textDirection, child: stack);

/*return Stack(
children: [
WidgetSizedBox(
child: animatedSizeWidget(pseudoChildKey),
),
loaded
? loadedChild
: Positioned.fill(
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
double radius = min(widget.maxLoadingCircleSize ?? double.infinity,
min(constraints.maxWidth, constraints.maxHeight)) /
2 -
widget.dotRadius / 2;
double x = constraints.maxWidth / 2;
double y = constraints.maxHeight / 2;
double maxAppearingRadius = max(constraints.maxWidth, constraints.maxHeight) / 2;
double appearingRadius =
widget.dotRadius + _appearingAnimation.value * (maxAppearingRadius - widget.dotRadius);
return Container(
child: appearing || disappearing
? ClipOval(
clipper:
CircleClipper(x + widget.dotRadius, y - radius + widget.dotRadius, appearingRadius),
child: Stack(children: [
loadedChild,
Opacity(
opacity: 1 - appearingRadius / maxAppearingRadius,
child: Container(
width: constraints.maxWidth,
height: constraints.maxHeight,
color: widget.dotColor ?? theme.accentColor,
))
]),
)
: Stack(
children: <Widget>[
WidgetSizedBox(
child: loadedChild,
),
] +
_animations.map((e) {
double radian = 0.5 * pi - 2 * pi * e.value;
return Positioned(
child:
widget.dotBuilder?.call(widget.dotRadius) ?? loadingPoint(widget.dotRadius),
top: y - radius * sin(radian),
left: x - radius * cos(radian),
);
}).toList()),
);
},
),
),
],
);*/
}

Widget loadingPoint(double radius) {
Expand All @@ -333,48 +276,17 @@ class _CircularWidgetLoadingState extends State<CircularWidgetLoading> with Tick
}
}

class CircleClipper extends CustomClipper<Rect> {
final double radius;
final double x, y;

CircleClipper(this.x, this.y, this.radius);

@override
Rect getClip(Size size) {
return Rect.fromCircle(center: Offset(x, y), radius: radius);
}

@override
bool shouldReclip(covariant CustomClipper<Rect> oldClipper) {
return this != oldClipper;
}

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is CircleClipper &&
runtimeType == other.runtimeType &&
radius == other.radius &&
x == other.x &&
y == other.y;

@override
int get hashCode => radius.hashCode ^ x.hashCode ^ y.hashCode;
}

class DotClipper extends CustomClipper<Rect> {
class _DotClipper extends CustomClipper<Rect> {
final double factor;
final double dotRadius;
final double maxLoadingCircleSize;
final double loadingCirclePadding;

DotClipper(this.factor, this.dotRadius, this.maxLoadingCircleSize, this.loadingCirclePadding);
_DotClipper(this.factor, this.dotRadius, this.maxLoadingCircleSize, this.loadingCirclePadding);

@override
Rect getClip(Size size) {
double radius =
min(maxLoadingCircleSize, min(size.width, size.height) - 2 * loadingCirclePadding) / 2 -
dotRadius;
double radius = min(maxLoadingCircleSize, min(size.width, size.height) - 2 * loadingCirclePadding) / 2 - dotRadius;
double x = size.width / 2;
double y = size.height / 2;

Expand Down
50 changes: 48 additions & 2 deletions lib/src/widgets/loading_widget.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,52 @@
import 'package:flutter/material.dart';
import 'package:widget_loading/src/utils/loading_state.dart';

abstract class LoadingWidget {
abstract class LoadingWidget extends StatefulWidget {
final Widget child;

/// Indicates whether the widget/data is loaded.
final bool loading;

/// Duration of the AnimatedSize. For deactivating AnimatedSize you can use [animatedSize].
final Duration sizeDuration;

/// Duration of the appearing/disappearing of the [child].
final Duration appearingDuration;

/// Duration of the loading-animation.
final Duration loadingDuration;

/// Curve of the AnimatedSize. For deactivating AnimatedSize you can use [animatedSize].
final Curve sizeCurve;

/// Curve of the appearing/disappearing of the [child].
final Curve appearingCurve;

/// Curve of the loading-animation.
final Curve loadingCurve;

/// Padding of child
final EdgeInsetsGeometry padding;

/// Activating/deactivating AnimatedSize-Wrapper of [child].
final bool animatedSize;

const LoadingWidget(
{Key? key,
this.loading = true,
this.sizeDuration = const Duration(milliseconds: 500),
this.appearingDuration = const Duration(milliseconds: 500),
this.loadingDuration = const Duration(milliseconds: 500),
this.sizeCurve = Curves.linear,
this.appearingCurve = Curves.fastOutSlowIn,
this.loadingCurve = Curves.easeInOutCirc,
this.padding = EdgeInsets.zero,
this.animatedSize = true,
required this.child})
: super(key: key);
}

abstract class LoadingWidgetState {
LoadingState _loadingState = LoadingState.LOADED;

set loadingState(LoadingState value) {
Expand All @@ -14,4 +60,4 @@ abstract class LoadingWidget {
bool get loading => _loadingState == LoadingState.LOADING;

bool get loaded => _loadingState == LoadingState.LOADED;
}
}
15 changes: 15 additions & 0 deletions lib/src/widgets/widget_sized_box.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:flutter/material.dart';

class WidgetSizedBox extends StatelessWidget {
final Widget child;

const WidgetSizedBox({Key? key, required this.child}) : super(key: key);

@override
Widget build(BuildContext context) {
return Opacity(
child: child,
opacity: 0.0,
);
}
}
Loading

0 comments on commit 390988b

Please sign in to comment.