hacktons / convex_bottom_bar

A Flutter package which implements a ConvexAppBar to show a convex tab in the bottom bar. Theming supported.
https://bar.hacktons.cn
Apache License 2.0
801 stars 151 forks source link

How to make tabBar item responsive? #139

Open NTMS2017 opened 3 years ago

NTMS2017 commented 3 years ago

Hi,

With a custom appear sample I try to make tabBar item responsive but seems margin and StyleHook is not allow me to make a more responsive.

For my app I use flutter_screenutil and auto_size_text plugin for responsive ui design. But can't make to work with tabor item.

Without modification (still not work as expected) the appear item looks too small on iPad mini4. With current modification image is below.

Also I couldn't find any "tabContent" example and usage in your example apps. It looks If I can modify tabContent I might be able to make tabor items more responsive.

Any idea?

Note: In main.dart I use ScreenUtilInit(designSize: Size(360, 690),... for my design draft. I can change a different UI draft but output still same.

import 'package:auto_size_text/auto_size_text.dart';
import 'package:convex_bottom_bar/convex_bottom_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:ntms_test_app/PageC.dart';
import 'package:ntms_test_app/pageA.dart';
import 'package:ntms_test_app/pageB.dart';

double myWidth;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SystemChrome.setEnabledSystemUIOverlays([]);
  await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
        designSize: Size(360, 690),
        allowFontScaling: true,
        builder: () => MaterialApp(
            debugShowCheckedModeBanner: false,
            title: 'Flutter Demo',
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: HomePage()));
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  int _currentIndex = 0;
  List<Color> _myColors = [Colors.green, Colors.red, Colors.blue];

  List<TabItem> items = <TabItem>[
    TabItem(icon: Icons.home, title: 'Home'),
    TabItem(icon: Icons.map, title: 'Discovery'),
    TabItem(icon: Icons.plus_one, title: 'Add'),
  ];

  Color pageColor;

  List<Widget> listWidgets = [PageA(myColor: Colors.green), PageB(myColor: Colors.red), PageC(myColor: Colors.blue)];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    myWidth = MediaQuery.of(context).size.width;
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: AutoSizeText(
          'Custom ConvexAppBar',
          style: TextStyle(color: Colors.black, fontSize: 18.0.ssp),
        ),
        backgroundColor: _myColors[_currentIndex],
      ),
      body: listWidgets[_currentIndex],
      bottomNavigationBar: StyleProvider(
        style: Style(),
        child: ConvexAppBar(
          disableDefaultTabController: false,
          height: MediaQuery.of(context).size.width > 360 ? 70 : 50,
          top: MediaQuery.of(context).size.width > 360 ? -60 : -30,
          curveSize: MediaQuery.of(context).size.width > 360 ? 100 : 75,
          style: TabStyle.react,
          items: [
            TabItem(
              title: '2019',
              icon: Icon(
                Icons.link,
                color: _myColors[0],
                size: MediaQuery.of(context).size.width > 360 ? 40 : 20,
              ),
            ),
            TabItem(
                title: '2020',
                icon: Icon(
                  Icons.contact_page,
                  color: _myColors[1],
                  size: MediaQuery.of(context).size.width > 360 ? 40 : 20,
                )),
            TabItem(
                title: "2021",
                icon: Icon(
                  Icons.work,
                  color: _myColors[2],
                  size: MediaQuery.of(context).size.width > 360 ? 40 : 20,
                )),
          ],
          backgroundColor: Colors.yellow,
          activeColor: Colors.red,
          color: Colors.black,
          onTap: (i) {
            debugPrint('click $i');
            setState(() {
              _currentIndex = i;
              pageColor = _myColors[i];
            });
          },
        ),
      ),
    );
  }
}

/// CLASS STYLE
class Style extends StyleHook {
  @override
  double get activeIconSize => 40;

  @override
  double get activeIconMargin => 10;

  @override
  double get iconSize => 20;

  @override
  TextStyle textStyle(Color color) {
    return TextStyle(fontSize: 20.0.ssp);
  }
}
Screenshot 2021-03-27 at 13 48 20
NTMS2017 commented 3 years ago

This is best I can make it to responsive. But for iPad the icon size is not changing.

SDK:

environment:
  sdk: ">=2.7.0 <3.0.0"

Plugin:

  cupertino_icons: ^1.0.2
  flutter_screenutil: ^5.0.0-nullsafety.11
  auto_size_text: ^3.0.0-nullsafety.0
  convex_bottom_bar: ^3.0.0

CODE:

import 'package:auto_size_text/auto_size_text.dart';
import 'package:convex_bottom_bar/convex_bottom_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:ntms_test_app/PageC.dart';
import 'package:ntms_test_app/pageA.dart';
import 'package:ntms_test_app/pageB.dart';

double myWidth;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SystemChrome.setEnabledSystemUIOverlays([]);
  await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
        designSize: Size(360, 690),
        allowFontScaling: true,
        builder: () => MaterialApp(
            debugShowCheckedModeBanner: false,
            title: 'Flutter Demo',
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: HomePage()));
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  int _currentIndex = 0;
  List<Color> _myColors = [Colors.green, Colors.red, Colors.blue];

  List<TabItem> items = <TabItem>[
    TabItem(icon: Icons.home, title: 'Home'),
    TabItem(icon: Icons.map, title: 'Discovery'),
    TabItem(icon: Icons.plus_one, title: 'Add'),
  ];

  Color pageColor;

  List<Widget> listWidgets = [PageA(myColor: Colors.green), PageB(myColor: Colors.red), PageC(myColor: Colors.blue)];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    myWidth = 1.sw;
    print("WIDTH: $myWidth");
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: AutoSizeText(
          'Custom ConvexAppBar',
          style: TextStyle(color: Colors.black, fontSize: 18.0.ssp),
        ),
        backgroundColor: _myColors[_currentIndex],
      ),
      body: listWidgets[_currentIndex],
      bottomNavigationBar: StyleProvider(
        style: Style(),
        child: ConvexAppBar(
          disableDefaultTabController: true,
          height: myWidth > 320 ? 70 : 50,
          top: myWidth > 320 ? -50 : -30,
          curveSize: myWidth > 320 ? 150 : 100,
          style: TabStyle.react,
          items: [
            TabItem(
              title: '2019',
              icon: Icon(
                Icons.link,
                color: _myColors[0],
              ),
            ),
            TabItem(
                title: '2020',
                icon: Icon(
                  Icons.contact_page,
                  color: _myColors[1],
                )),
            TabItem(
                title: "2021",
                icon: Icon(
                  Icons.work,
                  color: _myColors[2],
                )),
          ],
          backgroundColor: Colors.yellow,
          activeColor: Colors.red,
          color: Colors.black,
          onTap: (i) {
            debugPrint('click $i');
            setState(() {
              _currentIndex = i;
              pageColor = _myColors[i];
            });
          },
        ),
      ),
    );
  }
}

/// CLASS STYLE
class Style extends StyleHook {
  @override
  double get activeIconSize => myWidth > 320 ? 70 : 40;

  @override
  double get activeIconMargin => myWidth > 320 ? 15 : 10;

  @override
  double get iconSize => myWidth > 320 ? 35.ssp : 25.ssp;

  @override
  TextStyle textStyle(Color color) {
    return TextStyle(fontSize: myWidth > 320 ? 18.0.ssp : 16.0.ssp, fontWeight: FontWeight.bold);
  }
}

listWidgets A

import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

/// PAGE A
class PageA extends StatefulWidget {
  final Color myColor;

  const PageA({Key key, this.myColor}) : super(key: key);

  @override
  _PageAState createState() => _PageAState();
}

class _PageAState extends State<PageA> {
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          Center(
              child: AutoSizeText(
            'Entry A',
            style: TextStyle(fontSize: 20.0.ssp, fontWeight: FontWeight.bold, color: widget.myColor),
          )),
        ],
      ),
    );
  }
}

IMAGE:

Screenshot 2021-03-28 at 09 58 34
avenwu commented 3 years ago

@NTMS2017 The default example look fine on iPad mini4, so are you trying to make icon bigger on iPad? One more thing, I would suggest you ti provide two different style class, such as StyleIPad, StlyePhone to simplify the hook.

/// CLASS STYLE
class Style2 extends StyleHook {
  @override
  double get activeIconSize => 40 ;

  @override
  double get activeIconMargin => 5;

  @override
  double get iconSize => 50;

  @override
  TextStyle textStyle(Color color) {
    return TextStyle(fontSize: 12.0, fontWeight: FontWeight.bold);
  }
}
Screen Shot 2021-04-06 at 11 27 14

The style feature is limited. So if you can not make the tab to satisfy your case, you can make a custom one with other constructor, which allow you to define the tab by yourself.

  /// Define a custom tab style by implement a [DelegateBuilder].
  ///
  /// ```dart
  /// ConvexAppBar(
  ///   count: 5,
  ///   itemBuilder: Builder(),
  /// )
  ///
  /// class Builder extends DelegateBuilder {
  ///   @override
  ///   Widget build(BuildContext context, int index, bool active) {
  ///     return Text('TAB $index');
  ///   }
  /// }
  /// ```
  const ConvexAppBar.builder({
    Key? key,
    required this.itemBuilder,
    required this.count,
    this.initialActiveIndex,
    this.disableDefaultTabController = false,
    this.onTap,
    this.onTapNotify,
    this.controller,
    this.backgroundColor,
    this.gradient,
    this.height,
    this.curveSize,
    this.top,
    this.elevation,
    this.cornerRadius,
    this.curve = Curves.easeInOut,
    this.chipBuilder,
  }) 
NTMS2017 commented 3 years ago

Yes I am trying to make icon bigger on iPad. I will try your suggestion to make 2 different style. And write here the result

NTMS2017 commented 3 years ago

Sorry :( couldn't make it. Do you have any custom (Define a custom tab style by implement a [DelegateBuilder].) example? If you can provide I will appreciated. Thanks

avenwu commented 3 years ago

Checkout https://github.com/hacktons/convex_bottom_bar#custom-example

vytautas-pranskunas- commented 1 year ago

@avenwu you are saying there you can customize everything, yes you are right.. but alsmot from scratch because you are not exposing things like TransitionContainer. and similar.