Skip to content

Instantly share code, notes, and snippets.

@DevKhalyd
Last active February 7, 2021 04:07
Show Gist options
  • Save DevKhalyd/dedae5e8314de0bdbb1d6f91e9699ab3 to your computer and use it in GitHub Desktop.
Save DevKhalyd/dedae5e8314de0bdbb1d6f91e9699ab3 to your computer and use it in GitHub Desktop.
Mini Widgets to make easier the develop of an app
import 'package:flutter/gestures.dart';
///THIS FILE CONTAINS A LOT OF WIDGET USEFUL
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../utils/utils.dart';
class CenterText extends StatelessWidget {
const CenterText(this.text, {this.textAlign = TextAlign.center});
final String text;
final TextAlign textAlign;
@override
Widget build(BuildContext context) => Center(
child: Text(
text,
textAlign: textAlign,
),
);
}
class CircularProgressCustom extends StatelessWidget {
const CircularProgressCustom({this.color = Colors.orange});
final Color color;
@override
Widget build(BuildContext context) => Center(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(color),
),
);
}
///Default to vertical
class Space extends StatelessWidget {
const Space(this.space, {this.isHorizontal = false});
final double space;
final bool isHorizontal;
@override
Widget build(BuildContext context) => isHorizontal
? SizedBox(
width: _getSpace(context) * space,
)
: SizedBox(
height: _getSpace(context) * space,
);
double _getSpace(BuildContext context) => isHorizontal
? MediaQuery.of(context).size.width
: MediaQuery.of(context).size.height;
}
class TextFormFieldCustom extends StatelessWidget {
const TextFormFieldCustom(
{this.controller,
@required this.labelText,
this.errorText,
this.onTap,
this.paddingHorizontal,
this.paddingVertical,
this.helperText,
this.helperStyle,
this.labelStyle,
this.keyboardType,
this.inputFormatters,
this.validator,
this.onSaved,
this.prefixIcon,
this.suffixIcon,
this.initialValue,
this.enabled,
this.textCapitalization = TextCapitalization.none,
this.maxLines = 1,
this.expands = false,
this.textAlign = TextAlign.justify,
this.colorBorder = Colors.blue,
this.isUnderLine = true,
this.obscureText = false,
this.readOnly = false,
this.paddingAll = 16})
: super();
final TextEditingController controller;
final String labelText, helperText;
final double paddingAll, paddingHorizontal, paddingVertical;
final String errorText, initialValue;
final bool readOnly, obscureText, enabled;
final VoidCallback onTap;
final TextStyle helperStyle, labelStyle;
final TextAlign textAlign;
final Color colorBorder;
final bool isUnderLine, expands;
final TextInputType keyboardType;
final List<TextInputFormatter> inputFormatters;
final String Function(String) validator;
final void Function(String) onSaved;
final Widget prefixIcon, suffixIcon;
final maxLines;
final TextCapitalization textCapitalization;
@override
Widget build(BuildContext context) {
if ((paddingHorizontal != null && paddingVertical == null) ||
(paddingHorizontal == null && paddingVertical != null)) {
throw new Exception('Padding Horizontal and Verticalshould be non-null');
}
return Padding(
padding: paddingHorizontal != null && paddingVertical != null
? EdgeInsets.symmetric(
horizontal: paddingHorizontal, vertical: paddingVertical)
: EdgeInsets.all(paddingAll),
child: TextFormField(
textCapitalization: textCapitalization,
inputFormatters: inputFormatters,
keyboardType: keyboardType,
readOnly: readOnly,
onTap: onTap,
obscureText: obscureText,
controller: controller,
textAlign: textAlign,
cursorColor: colorBorder,
validator: validator,
onSaved: onSaved,
initialValue: initialValue,
maxLines: maxLines,
expands: expands,
enabled: enabled,
decoration: InputDecoration(
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
focusedBorder: isUnderLine
? UnderlineInputBorder(
borderSide: BorderSide(
color: colorBorder,
),
)
: OutlineInputBorder(
borderSide: BorderSide(
color: colorBorder,
),
borderRadius: BorderRadius.circular(24.0)),
enabledBorder: isUnderLine
? UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
)
: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
borderRadius: BorderRadius.circular(24.0)),
errorBorder: isUnderLine
? UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
),
)
: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
),
borderRadius: BorderRadius.circular(24.0)),
focusedErrorBorder: isUnderLine
? UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
),
)
: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
),
borderRadius: BorderRadius.circular(24.0)),
labelText: labelText,
labelStyle: labelStyle,
errorText: errorText,
helperText: helperText,
helperStyle: helperStyle,
),
),
);
}
}
class ListViewCustom<T> extends StatelessWidget {
final List<T> items;
final Widget Function(BuildContext, int) builder;
final bool shrinkWrap, reverse;
final ScrollController controller;
const ListViewCustom(this.items,
{this.builder,
this.controller,
this.shrinkWrap = false,
this.reverse = false});
@override
Widget build(BuildContext context) => ListView.builder(
controller: controller,
reverse: reverse,
shrinkWrap: shrinkWrap,
itemCount: items?.length ?? 0,
itemBuilder: builder ??
(_, i) {
return ListTile(
title: Text('Item $i'),
);
});
}
//typedef Widget BuilderFuture(BuildContext context, AsyncSnapshot snapshot);
class FutureBuildCustom<T> extends StatelessWidget {
final Future<T> future;
final Widget onNoData;
final Widget onLoading;
final Widget Function(BuildContext context, AsyncSnapshot<T> snapshot)
onResponse;
const FutureBuildCustom({
@required this.future,
this.onResponse,
this.onNoData,
this.onLoading,
});
@override
Widget build(BuildContext context) => FutureBuilder(
future: future,
builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
if (snapshot.hasData) {
if (onResponse == null) return CenterText('Data');
return onResponse(context, snapshot);
}
if (!snapshot.hasData &&
snapshot.connectionState == ConnectionState.done) {
return onNoData ??
IconDescription(Icons.block, 'No hay datos para mostrar');
} else {
return onLoading ?? CircularProgressCustom();
}
},
);
}
class StreamBuilderCustom<T> extends StatelessWidget {
final Stream<T> stream;
///When the `stream emits null`
final Widget onNoData;
///When the `stream Connection == !Connection.Done`
final Widget onLoading;
///When the `stream emits a non-null value`
final Widget Function(BuildContext context, AsyncSnapshot<T> snapshot)
onResponse;
const StreamBuilderCustom({
@required this.stream,
this.onResponse,
this.onNoData,
this.onLoading,
});
@override
Widget build(BuildContext context) => StreamBuilder<T>(
stream: stream,
builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
final infoWidget = (String msg) => IconDescription(Icons.block, msg);
if (snapshot.hasData && !snapshot.hasError) {
if (onResponse == null) return CenterText('There is data');
return onResponse(context, snapshot);
}
if (!snapshot.hasData &&
snapshot.connectionState == ConnectionState.done ||
snapshot.hasError)
return onNoData ?? infoWidget('No hay datos para mostrar');
if (ConnectionState.waiting == snapshot.connectionState)
return onLoading ?? CircularProgressCustom();
return infoWidget('Ha ocurrido un error, intente de nuevo más tarde');
},
);
}
class ButtonCustom extends StatelessWidget {
final void Function() onPressed;
final String btnText;
final Color colorBtn, colorTextRaised;
final TextStyle styleText;
final bool isRaised;
final IconData iconData;
final double paddingH, paddingV;
const ButtonCustom(this.btnText,
{this.onPressed,
this.styleText,
this.iconData,
this.paddingH = 0,
this.paddingV = 0,
this.colorTextRaised,
this.colorBtn = Colors.blue,
this.isRaised = false})
: assert(colorTextRaised == null || styleText == null);
@override
Widget build(BuildContext context) => !isRaised ? flat() : raised();
Widget flat() => FlatButton(
padding: EdgeInsets.symmetric(horizontal: paddingH, vertical: paddingV),
color: colorBtn,
onPressed: onPressed ??
() {
print('Pressed $btnText');
},
child: Text(
btnText,
style: styleText ?? TextStyle(color: Colors.white),
));
Widget raised() {
return RaisedButton(
padding: EdgeInsets.symmetric(horizontal: paddingH, vertical: paddingV),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
side: BorderSide(color: colorBtn)),
onPressed: onPressed,
color: colorBtn,
textColor: colorTextRaised ?? Colors.white,
child: iconData == null
? Text(btnText, style: styleText ?? TextStyle(fontSize: 14))
: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(iconData),
Space(
0.01,
isHorizontal: true,
),
Text(btnText, style: styleText ?? TextStyle(fontSize: 14))
],
),
);
}
}
///Set the [one] Colors.black and [two] Colors.white
///
///[onPressed] is called when the text is pressed
class RichTextCustom extends StatelessWidget {
final String one, two;
final bool reversed;
final VoidCallback onPressed;
final double fontSize;
const RichTextCustom(this.one, this.two,
{this.onPressed, this.fontSize, this.reversed = false});
@override
Widget build(BuildContext context) => RichText(
text: TextSpan(
text: one,
recognizer: TapGestureRecognizer()..onTap = onPressed,
style: TextStyle(
color: Colors.black,
fontSize: fontSize,
fontWeight: !reversed ? FontWeight.bold : FontWeight.normal,
),
children: <TextSpan>[
TextSpan(
text: two,
recognizer: TapGestureRecognizer()..onTap = onPressed,
style: TextStyle(
color: !reversed ? Colors.grey : Colors.black,
fontSize: fontSize,
fontWeight: !reversed ? FontWeight.normal : FontWeight.bold,
)),
],
),
);
}
class IconDescription extends StatelessWidget {
final IconData icon;
final String msg;
const IconDescription(this.icon, this.msg);
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
icon,
size: getWidgetPixels(context) * 0.3,
color: Colors.grey,
),
Space(0.01),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
msg,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey),
),
)
],
),
);
}
}
///`customPadding` refers to a `EdgeInsetsGeometry`
///`allPadding` refers to `all` propierty
///`top,left,bottom,right` refers to `only` propierty
class PaddingCustom extends StatelessWidget {
final Widget child;
//A full customizable padding
final EdgeInsetsGeometry customPadding;
final double allPadding;
final double top, left, right, bottom;
const PaddingCustom(
{@required this.child,
this.customPadding,
this.allPadding,
this.top = 0.0,
this.left = 0.0,
this.right = 0.0,
this.bottom = 0.0});
@override
Widget build(BuildContext context) {
EdgeInsetsGeometry usePadding = EdgeInsets.all(0);
bool shouldUseSides = top > .0 || bottom > .0 || left > .0 || right > .0;
assert(allPadding == null || !shouldUseSides);
if (shouldUseSides) {
usePadding =
EdgeInsets.only(top: top, bottom: bottom, left: left, right: right);
}
if (allPadding != null) {
usePadding = EdgeInsets.all(allPadding);
}
if (customPadding != null) usePadding = customPadding;
return Padding(
padding: usePadding,
child: child,
);
}
}
class ListTileDefault extends StatelessWidget {
final IconData icon;
final String title, description;
final VoidCallback onTap;
const ListTileDefault({
@required this.icon,
@required this.title,
@required this.description,
this.onTap,
});
@override
Widget build(BuildContext context) => ListTile(
leading: Icon(icon),
title: Text(
title,
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(description),
onTap: onTap,
);
}
class CheckBoxLisTileCustom extends StatelessWidget {
final String title;
final IconData icon;
final bool isEnabled;
final void Function(bool) onChanged;
const CheckBoxLisTileCustom(
{@required this.title,
@required this.icon,
@required this.isEnabled,
this.onChanged});
@override
Widget build(BuildContext context) => CheckboxListTile(
title: Text(title),
secondary: Icon(icon),
value: isEnabled,
onChanged: onChanged);
}
class SwitchTileCustom extends StatelessWidget {
final String txt;
///The switch is active or not
final bool isActive;
final Function(bool) onChanged;
final IconData icon;
final VoidCallback onTap;
final Widget subtitle;
const SwitchTileCustom(
{@required this.txt,
this.subtitle,
this.onChanged,
this.icon = Icons.lightbulb_outline,
this.isActive = false,
this.onTap});
@override
Widget build(BuildContext context) => SwitchListTile(
value: isActive,
onChanged: onChanged,
secondary: Icon(icon),
title: Text(
txt,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
subtitle: InkWell(
child: subtitle,
onTap: onTap,
),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment