当前位置:网站首页>Flutter -- realize the tabbar switching effect of Netease cloud music

Flutter -- realize the tabbar switching effect of Netease cloud music

2022-06-22 12:26:00 Still waters run deep zz

Introduce

Preview

analysis

The effect is very simple , When switching , The corresponding text should be reduced / Zoom in .

Let's implement this customization tabbar

Realization

First we define a class

class CustomTabBar extends WidgetState with SingleTickerProviderStateMixin

Because of animation , So it needs to be mixed with

SingleTickerProviderStateMixin

CustomTabBar

First, you need to define two callbacks

// Because I use MVVM, So we need to tabbar Of vm Efferent , Convenient outer layer control tabbar
typedef TabBarController = void Function(TabBarViewModel controller);
// When we click tab Of item When , Need to correspond to index Efferent  , The outer layer can be switched pageView
typedef TabClick = void Function(int index);

Two variables are used to control the coefficient threshold of text magnification

  final double min = 1.0;
  final double max = 1.2;
  
  /// Animation 
  AnimationController controller;
  Animation animation;
  

Next, let's look at the initialization of variables

  @override
  void initState() {
    super.initState();
    // Animation is fast   Only 50ms
    controller = AnimationController(duration: Duration(milliseconds: 50),vsync: this);
    // Animation controls the enlargement and reduction of text 
    animation = Tween<double>(begin: min,end: max).animate(controller);
    controller.addListener(() {
    	// Monitor the animation ,
        // And call updateFactor() Method 
      if(!parentVM.isResetting){
        parentVM.updateFactor(animation.value);
      }

    });
    controller.addStatusListener((status) {
      if(status == AnimationStatus.completed){
      	// When the animation is finished , We reset the animation , The reset here makes our own way 
        // Instead of calling directly controller Of 
        parentVM.resetController();
      }
    });
  }

So let's see updateFactor() and resetController() Method

 // This variable is used to zoom in and out the font 
  double textScaleFactor = 1.2;
  updateFactor(double newV){
  	// We will animate value Send in updates textScaleFactor
    // The following expression , To ensure that   This amplification factor   stay 1-1.2 Between 
    textScaleFactor = newV > textScaleFactor ? newV.clamp(1.0, 1.2) : textScaleFactor;
    notifyListeners();
  }
	// Used here to define controller Of reset, 
    // avoid controller reset when , Reduced font size , So add this variable 
  bool isResetting = false;
  void resetController(){
   // As you can see from the code above ,( Monitor the animation part )
   //reset=true When , Page refresh will not be triggered 
    isResetting = true;
    controller.reset();
    // After the reset, set the status to false
    isResetting = false;
  }

Next, let's look at the layout

          return Container(
            color: Colors.white,
            height: getWidthPx(80),
            child: buildTab(),
          );
          
          
  static const double txtSize = 36;
  Widget buildTab() {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.end,
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: <Widget>[
        wrap(TabBarItem(parentVM, ' my ', 0,textSize: getSp(txtSize)).generateWidget(),0),
        wrap(TabBarItem(parentVM, ' Find out ', 1,textSize: getSp(txtSize)).generateWidget(),1),
        wrap(TabBarItem(parentVM, ' Yuncun ', 2,textSize: getSp(txtSize)).generateWidget(),2),
        wrap(TabBarItem(parentVM, ' video ', 3,textSize: getSp(txtSize)).generateWidget(),3),

      ],
    );
  }

  Widget wrap(Widget child,int index){
    return GestureDetector(
      onTap: (){
        tabClick(index);
      },
      child: Container(
        alignment: Alignment.bottomCenter,
        width: getWidthPx(110),
        child: child,
      ),
    );
  }

The code is simple , Basic 4 individual tab item The horizontal layout , there item It's our custom , Will be introduced later

We mainly look at this method , He will trigger the animation

tabClick(index);// This is our callback , In the end item Of index To the outer page 

Let's look at the animation trigger of the outer page

Page animation triggers

The code below , It's the layout of the page , Abbreviated here homePage, This customization tab There will be one with pageview binding

  buildTab() {
    return Container(
      height: getWidthPx(80),
      //color: Colors.greenAccent,
      child: CustomTabBar((controller){
        tabController = controller;
      },(index){
        //tab click
        pageController.jumpToPage(index);
      }).generateWidget(),
    );
  }
  
  ///pageview Of   Code ( Abridged edition )
  
  PageView(
      controller: pageController,
      onPageChanged: (index){
        tabController.switchPage(index);
        pageIndex = index;
      },
      ...)
  

Let's go through the process according to the callback in the previous section , When the callback is triggered , It will send out pageview Handoff

	(index){
        //tab click
        pageController.jumpToPage(index);
      }

and pageview After switching , It will trigger its own callback

onPageChanged: (index){
		//page view The callback of triggers  tab Of switchPage(index) Method 
        tabController.switchPage(index);
        pageIndex = index;
      }

Remember tabcontroller Do you ? It is actually custom tab Of VM Sure , Let's take a look at its switchPage(index) Method

  switchPage(int index){
   // We will tab Of  index Configure as and  pageview  Match 
    pageIndex = index;
    // below 
    record();
    // Refresh the interface 
    notifyListeners();
    // Execute zoom in animation 
    controller.forward();
  }
  // This method we use to record tab  Of  item index
  // Because the goal is index To zoom in , And the former item Then you have to shrink ,
  // It is equivalent to a switching history 
  // Always record only two values 
  List<int> indexRecord = [];
    void record() {
    if(indexRecord.length == 3) indexRecord.removeAt(0);
    indexRecord.add(pageIndex);
  }
  

This pageindex And the corresponding historical records , You can control item The zoom out and zoom in , Let's see item The implementation of the .

tabbar item

Explain that I will write in the notes

class TabBarItem extends WidgetState {
	// The outer vm, This vm There are many ways to obtain , It is convenient for me to pass parameters to this constructor 
  final TabBarViewModel parentVM;
  final String text;// copy 
  final double textSize;// font size 
  final index;// Every item Of   identification   It's usually  0,1,2,3

  TabBarItem(this.parentVM,this.text,this.index,{this.textSize = 20})
    :assert(parentVM!=null),assert(text.isNotEmpty);




  @override
  void initState() {
    super.initState();

  }


  @override
  Widget build(BuildContext context) {
   // The expression here is more around 
   // In short , It is based on what we said above  pageIndex and  recordList Historical record 
   // To get the current currentIndex and   the previous  preIndex
   // currentIndex  We'll zoom in 
   // preIndex   We will shrink accordingly 
    return Text(text,
     // We go through textScaleFactor Come on   Enlarge the font 
      textScaleFactor:(index == parentVM.pageIndex
          ?parentVM.textScaleFactor :
            (index == parentVM.getLastIndex())
                ? parentVM.textScaleFactor : parentVM.min) ,
      style: TextStyle(fontSize: textSize,
        color: index == parentVM.pageIndex?Colors.black:Colors.grey),);
  }

}

So far, the whole function has been developed , Thank you for reading

If there are shortcomings , Welcome to point out

Demo

Internal search is enough

Demo Address - github

原网站

版权声明
本文为[Still waters run deep zz]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/173/202206221202225278.html