introduce

Part I: Flutter – a price range filter that mimes Airbnb. (a)

Part 2: The Price range filter of Flutter – mimicairbnb. (2)

Part 3: Plotting Bezier Curves with Flutter-CustomPaint

The product required to copy the effect of Airbnb. I looked at it and thought it was a great interaction.

Analysis of the

After observation, I divided it into two parts: chart and bottom slider. The chart is further divided into the bottom table and the top table, the bottom is basically do not care about the background, the top need to change according to the slider.

In the top chart I came up with three implementations:

1. (with the help of MPchart) reset the Y value of the chart by the position of the slider to achieve the effect of cutting. It turns out that if the chart is linear Bezier, 0 causes troughs to overflow the X-axis due to the underlying control points. 2. Drawing charts by ourselves is the most flexible and potentially the most perfect implementation scheme, but it is very time-consuming, so I gave up due to the tight schedule. 3. (with the help of MPchart) it is still the top and bottom tables, and ClipPath is used for the top and bottom tables. (The actual effect is very good, can be used to achieve relatively perfect effect in a short time)Copy the code

implementation

Divide the price slider widget into the left, right, and middle black line widgets

Container( width: widget.rootWidth, height: widget.rootHeight, color: Colors.transparent, child: Stack( alignment: AlignmentDirectional bottomStart, overflow, overflow. Visible, the children: < widgets > / / / / the slider in the middle of the black line Positioned (bottom: 25, child: _lineBlock(context, widget.rootwidth),), /// left and right slider _leftImageBlock(context, widget.rootwidth), _rightImageBlock(context, widget.rootwidth), _rightImageBlock(context, widget.rootWidth), ], ), ),Copy the code

The horizontal padding is controlled by leftBlackLineW and rightBlackLineW, and the two variables are updated by the slider to achieve the dynamic change of the black line.

Stack(children: <Widget>[Container(color: Colors. Transparent, height: 5.0, width: screenWidth, alignment: Alignment.center, // padding: EdgeInsets.only(left: leftBlackLineW,right: rightBlackLineW), child: Container( color: Colors.black, height: 3, width: screenWidth , ), ), ], ),Copy the code

Implementation of slider:

_imageItem(GlobalKey key){// A key is used for positioningreturn Container(
      key: key,
      decoration: BoxDecoration(
        color: Colors.red,
        borderRadius: BorderRadius.circular(6)
      ),
      width: blockSize,
      height: blockSize*0.7,
    );
  }
Copy the code

The interaction between the left and right sliders is not fundamentally different from gestures, so here is an example of the left slider :(for code understanding, I will describe it in the comments)

_leftImageBlock(BuildContext context, double screenWidth) {

    returnPositioned( left: leftImageMargin, //top: 0, child: Stack( alignment: AlignmentDirectional.bottomCenter, overflow: Overflow.visible, children: <Widget>[ Column( crossAxisAlignment: CrossAxisAlignment.center, children: (Visible: isLeftDragging, Child: Text(_leftPrice,style: _leftdragging, dragging, dragging, dragging) TextStyle(fontSize: 12,color: color.black),),), // RootHeight *0.7,), // Left slider GestureDetector(Child: _imageItem(leftImageKey), // Move onHorizontalDragUpdate when dragging horizontally: (DragUpdateDetails Details) {/// details.delta.direction > 0 swipe left, less than =0 swipe right isLeftDragging =true;
                  if(leftImageMargin < 0) {// Handle the left edge to avoid slider overflow leftImageMargin = 0; LeftBlackLineW = 2; }elseMinimumDistance is the minimumDistance. It can be customized to your needs. The default is 5if (details.delta.direction <= 0
                      && ((screenWidth-(rightImageMargin+blockSize))-(leftImageMargin + blockSize))
                          <(singleW* minimumDistance)){
                    return ;
                  }
                  else{// Normal left margin update to achieve slider effect leftImageMargin += details.delt.dx; LeftBlackLineW = leftImageMargin+blockSize/2; } double _leftImageMarginFlag = leftImageMargin; // Refresh the price Indicator at the topfor(int i = 0; i< widget.list.length; i++){if(_leftImageMarginFlag < singleW * (0.5 + I)){_leftPrice = widget.list[I].x; // The selected index can be used as his leftImageCurrentIndex = I;break; }}setState(() {}); / / refresh the UIif(widget.leftSlidListener ! = null){ widget.leftSlidListener(true,leftImageCurrentIndex,leftImageKey); }}, /// drag to end onHorizontalDragEnd: (DragEndDetails Details) {// When the drag is finished, we need to calibrate the widget once to avoid image anomalies // Also require the slider to be only at two points in each price range, isLeftDragging = is also processed herefalse; // Make sure the slider exceeds the minimum spacing when sliding fast and short distancesif ( ((screenWidth-(rightImageMargin+blockSize))-(leftImageMargin+blockSize))<(singleW*5)){
                    setState(() {
                    });
                    return; } double _leftImageMarginFlag = leftImageMargin; /// After the drag is complete, the slider needs to be calibrated to ensure that the slider always falls on the end of the price rangefor(int i = 0; i< widget.list.length; i++){if(_leftImageMarginFlag < singleW * (0.5 + i)){
                      if(i == 0){
                        leftImageMargin = 0;
                      }else{
                        leftImageMargin = singleW * i;
                      }
                      _leftPrice = widget.list[i].x;
                      leftImageCurrentIndex = i;
                      break; }} leftBlackLineW = leftImageMargin + blockSize;setState(() {}); / / refresh the UIif(widget.leftSlidListener ! = null){ widget.leftSlidListener(false,leftImageCurrentIndex,leftImageKey); }},), // The price text at the bottom of the slider, "unavailable", unavailable or offstage Container(padding: EdgeInsets. Only (top: 6), child: Text(_leftPrice,style: TextStyle(fontSize: 12, color:! isLeftDragging ? Colors.black : Colors.white),), ) ], ), ], ), ); }Copy the code

conclusion

Since the original project used provider to control the state, the DEMO did not use it, so some variable transfer in the DEMO looks a little redundant, and some inexplicable widgets are nested, which is also caused by the deletion of some functions, please understand. I will make up the next part as soon as possible. 🙂 _

DEMO

Github.com/bladeofgod/…