Flutter Pageview.builder Advanced Vertical Animation | Height Scaling and Transition

Flutter Pageview.builder Advanced Vertical Animation | Height Scaling and Transition

    Flutter Pageview.builder in default, does not do horizontal or vertical scalling. If we want to do any kind of scaling within PageView.builder, We need to do this scaling based on scaling factor. Scaling factor could come from current value of the page. 

    If we get the page value, we would solve the height problem and height scalling.

    Download the starter code here

    Pageview.builder starter code

     

    Below is the function and code for getting page's value.

     PageController pageController = PageController(viewportFraction: 0.85);
      var _currPageValue = 0.0;
      @override
      void initState(){
        super.initState();
        pageController.addListener(() {
          setState(() {
            _currPageValue=  pageController.page!;
            print(_currPageValue);
          });
        });
      }

    To get page value we need to attach a listener to our page controller. That's what we did in the initState() function.

    And we want to update the page value immediately, we need to save it inside the setState() function.

    We need to get that value from the PageController(). Some must know important keys about Pageview.builder

    Current index value is same as page value

    Index value suddenly changes, but page value changes slowly

    Index value could be integer only, but page value have decimals

    Moving to the left, index and page value increases

    Moving to the right, index and page value decrease. Index value decreases imediately by one.

    At the end, we need to dispose the controller.

    @override
      void dispose() {
        super.dispose();
        pageController.dispose();
      }

     

    Entry of the Pageview.builder

    PageView.builder(
    
                        controller: pageController,
                        physics: BouncingScrollPhysics(),
                        itemCount: 5,
                        itemBuilder: (context, position) {
                          return _buildPageItem(position);
                        },
                      )

    In the PageView.builder() contstructor we need to use property for mentioning pageController.

     

    The algorithm to realise a smooth scaling for height. We also did the height transition here.

      //scale factor
      double _scaleFactor = .8;
      //view page height
      double _height = 230.0;
      _buildPageItem(int index) {
        Matrix4 matrix = new Matrix4.identity();
        
        if(index==_currPageValue.floor()){
          var currScale = 1-(_currPageValue-index)*(1- _scaleFactor );
          var currTrans = _height*(1-currScale)/2;
          matrix = Matrix4.diagonal3Values(1.0, currScale, 1.0)
          ..setTranslationRaw(0, currTrans, 0);
        }else if(index ==_currPageValue.floor()+1){
          var currScale = _scaleFactor+(_currPageValue-index+1)*(1- _scaleFactor );
          var currTrans = _height*(1-currScale)/2;
          matrix = Matrix4.diagonal3Values(1.0, currScale, 1.0)
            ..setTranslationRaw(0, currTrans, 0);
        }else if(index ==_currPageValue.floor()-1){
          var currScale = 1-(_currPageValue-index)*(1- _scaleFactor );
          var currTrans = _height*(1-currScale)/2;
          matrix = Matrix4.diagonal3Values(1.0, currScale, 1.0)
            ..setTranslationRaw(0, currTrans, 0);
        }else{
          var currScale = 0.8;
          matrix = Matrix4.diagonal3Values(1.0, currScale, 1.0)
          ..setTranslationRaw(0, _height*(1-_scaleFactor)/2, 0);
        }
    
        return Transform(
          transform: matrix,
          child: Padding(
            padding: EdgeInsets.symmetric(horizontal: 5),
            child:   GestureDetector(
              child: Align(
                alignment: Alignment.topCenter,
                child: Stack(
                  children: [
                    Container(
                      padding: const EdgeInsets.only(left: 20, top: 20),
                      height: 220,
                      width: MediaQuery.of(context).size.width-20,
                      margin: const EdgeInsets.only(right: 5, left: 5),
                      decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(30),
                          color:index.isEven?Color(0xFF69c5df):Color(0xFF9294cc),
                          image: DecorationImage(
                              fit: BoxFit.cover,
                              image: AssetImage(
                                  "img/food0.png"
                              )
                          )
                      ),
    
                    ),
                    Align(
                      alignment: Alignment.bottomCenter,
                      child: Container(
                        margin: const EdgeInsets.only(bottom: 40, left: 35, right: 35),
                        width: double.maxFinite,
                        height: 120,
    
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(20),
                            color:Colors.white,
                            boxShadow: [
                              BoxShadow(
                                  color: Color(0xFFe8e8e8),
                                  blurRadius: 5.0,
                                  offset: Offset(0, 5)
                              ),
                              BoxShadow(
                                  color: Colors.white,
                                  offset: Offset(-5, 0)
                              ),
                              BoxShadow(
                                  color: Colors.white,
                                  offset: Offset(5, 0)
                              )
    
                            ]
                        ),
                        child: Container(
                          padding: const EdgeInsets.only(top: 20, left: 15, right: 15),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text("Fruit nutrition meal"),
                              SizedBox(height: 10,),
                              Row(
                                children: [
                                  Wrap(
                                    children: List.generate(5, (index) => Icon(Icons.star, color:Colors.cyan, size:15)),
    
                                  ),
                                  SizedBox(width: 10,),
                                  TextWidget(text: "4.5", color: Color(0xFFccc7c5)),
                                  SizedBox(width: 10,),
                                  TextWidget(text: "1287 comments", color: Color(0xFFccc7c5))
                                ],
                              ),
                              SizedBox(height: 20,),
                  
                            ],
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      }

    Scaling can not be done without Matrix4 API in flutter. That's why we use this API, and pass the scaled value to the function called Matrix4.diagonal3Value() and Matrix4.setTransitionRaw()

    Matrix4.diagonal3Value() is for setting the scaling factor in x, y and z.

    Matrix4.setTransitionRaw() for changing the height position.

    Courses


    Recommended posts


    Recent posts