flutter 自定義slider和插件syncfusion_flutter_sliders使用

先上效果圖:

image.png

因?yàn)轫?xiàng)目需求,所以自定義一個(gè)slider.

使用:

MySliderUtil(
  minValue: (widget.model?.durableNow ?? 0) / 100, //可滑動(dòng)的最小值
  valueBlock: (value) {
    print(value);
),

具體代碼

class MySliderUtil extends StatefulWidget {
  MySliderUtil({
    Key? key,
    required this.valueBlock,
    this.minValue = 0.0,
  }) : super(key: key);

  final ValueBlock valueBlock;
  final double minValue;
  @override
  _MySliderUtilState createState() => _MySliderUtilState();
}

class _MySliderUtilState extends State<MySliderUtil> {
  double _value = 0.0;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _value = widget.minValue;
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: SAdapt.width(28),
      child: Stack(
        children: [
          Positioned(
            top: 8.w,
            child: Container(
              width: 12.w,
              height: 12.w,
              decoration: BoxDecoration(
                color: get826DD4Color(),
                borderRadius: BorderRadius.circular(10),
              ),
            ),
          ),
          Positioned(
            right: 0.w,
            top: 8.w,
            child: Container(
              width: 12.w,
              height: 12.w,
              decoration: BoxDecoration(
                color: getF5F9FCColor(),
                borderRadius: BorderRadius.circular(10),
              ),
            ),
          ),
          Container(
            margin: EdgeInsets.only(left: 11.5.w, right: 11.5.w),
            child: SliderTheme(
              data: SliderThemeData(
                //去掉長按光暈
                overlayColor: Colors.transparent,
                trackHeight: SAdapt.width(2),
                inactiveTrackColor: getF5F9FCColor(),
                activeTrackColor: get826DD4Color(), // Color(0xFF81C359),
                trackShape: const CustomTrackShape(),
                thumbShape: SquareSliderComponentShape(),
              ),
              child: Slider(
                value: _value < 0 ? 0 : _value,
                onChangeStart: (double value) {},
                onChangeEnd: (double value) {
                  if (value < widget.minValue) {
                    widget.valueBlock(widget.minValue);
                    return;
                  }
                  //每次借宿后都會(huì)走
                  // 拖拽跳轉(zhuǎn)
                  setState(() {
                    _value = value;
                  });
                  widget.valueBlock(value);
                },
                onChanged: (double value) {
                  if (value < widget.minValue) {
                    _value = widget.minValue;
                  } else {
                    _value = value;
                  }
                  setState(() {});
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

上面的其實(shí)就可以用了,但是需求的滑塊需要我們自定義,又遇到了別的問題,一步一步來~!

使用的時(shí)候發(fā)現(xiàn)滑塊選中的偏移量有一些問題,所以定義了如下的RoundedRectSliderTrackShape:

class CustomTrackShape extends RoundedRectSliderTrackShape {
  const CustomTrackShape();

  @override
  Rect getPreferredRect({
    required RenderBox parentBox,
    Offset offset = Offset.zero,
    required SliderThemeData sliderTheme,
    bool isEnabled = false,
    bool isDiscrete = false,
  }) {
    final double trackHeight = sliderTheme.trackHeight!;
    final double trackWidth = parentBox.size.width;
    final double trackLeft = offset.dx;
    final double trackTop =
        offset.dy + (parentBox.size.height - trackHeight) / 2;
    return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
  }

  @override
  void paint(
    PaintingContext context,
    Offset offset, {
    required RenderBox parentBox,
    required SliderThemeData sliderTheme,
    required Animation<double> enableAnimation,
    required TextDirection textDirection,
    required Offset thumbCenter,
    bool isDiscrete = false,
    bool isEnabled = false,
    double additionalActiveTrackHeight = 0,
  }) {
    super.paint(
      context,
      offset,
      parentBox: parentBox,
      sliderTheme: sliderTheme,
      enableAnimation: enableAnimation,
      textDirection: textDirection,
      thumbCenter: thumbCenter,
      //增加選中滑塊的高度,系統(tǒng)默認(rèn)+2· 給0就不加高了
      additionalActiveTrackHeight: 0,
    );
  }
}

最后我們來封裝滑塊的樣式:

class SquareSliderComponentShape extends SliderComponentShape {
  @override
  Size getPreferredSize(bool isEnabled, bool isDiscrete) {
    return Size(SAdapt.width(28), SAdapt.width(28));
  }

  @override
  void paint(PaintingContext context, Offset center,
      {required Animation<double> activationAnimation,
      required Animation<double> enableAnimation,
      required bool isDiscrete,
      required TextPainter labelPainter,
      required RenderBox parentBox,
      required SliderThemeData sliderTheme,
      required TextDirection textDirection,
      required double value,
      required double textScaleFactor,
      required Size sizeWithOverflow}) {
    final Canvas canvas = context.canvas;

    canvas.drawRRect(
      RRect.fromRectAndRadius(
        Rect.fromCenter(
            center: center, width: SAdapt.width(28), height: SAdapt.width(28)),
        const Radius.circular(14),
      ),
      Paint()..color = Colors.white,
    );

    //背景的線  實(shí)線
    Paint line = Paint()
      ..color = get826DD4Color()
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..strokeWidth = SAdapt.width(2);
//  畫圓方法
    canvas.drawCircle(center, SAdapt.width(14), line);
  }
}

如果對(duì)你有幫助的話,希望能給我點(diǎn)個(gè)贊,哈哈!

后續(xù)
項(xiàng)目里好多樣式的滑塊,后來引用了一個(gè)第三方:syncfusion_flutter_sliders,然后按照你的需求再進(jìn)行修改就可以了.

進(jìn)度條 兩個(gè)拖動(dòng)
#https://pub.dev/packages/syncfusion_flutter_sliders/versions 
syncfusion_flutter_sliders: ^20.3.52
修改進(jìn)度條樣式
# https://pub.dev/packages/syncfusion_flutter_core 
syncfusion_flutter_core: ^20.3.52

有各式各樣的,大致都能滿足我們使用的需求.下面是文檔:
https://help.syncfusion.com/flutter/slider/thumb-and-overlay

貼兩個(gè)使用的例子:
這個(gè)是雙滑塊的
先上效果圖


image.png

代碼:

Container(
  margin: EdgeInsets.only(
    bottom: SAdapt.width(15),
    left: SAdapt.width(15),
    right: SAdapt.width(15),
  ),
  child: Stack(
    children: [
      Positioned(
        // right: 21.w,
        left: 14.w,
        top: 19.w,
        child: Container(
          width: 12.w,
          height: 12.w,
          decoration: BoxDecoration(
            color: getF5F9FCColor(),
            borderRadius: BorderRadius.circular(10),
          ),
        ),
      ),
      Positioned(
        // right: 21.w,
        right: 14.w,
        top: 19.w,
        child: Container(
          width: 12.w,
          height: 12.w,
          decoration: BoxDecoration(
            color: getF5F9FCColor(),
            borderRadius: BorderRadius.circular(10),
          ),
        ),
      ),
      SfRangeSliderTheme(
        data: SfRangeSliderThemeData(
          overlayColor: Colors.transparent,
          thumbColor: Colors.white,
          thumbRadius: 12,
          thumbStrokeWidth: SAdapt.width(2),
          thumbStrokeColor: get826DD4Color(),
          activeTrackHeight: SAdapt.width(2),
          inactiveTrackHeight: SAdapt.width(2),
          activeTrackColor: get826DD4Color(),
        ),
        child: SfRangeSlider(
          min: 0.0,
          max: widget.maxRang,
          values: _values,
          interval: 20,
          showTicks: false,
          showLabels: false,
          enableTooltip: false,
          minorTicksPerInterval: 1,
          // activeColor: get826DD4Color(),
          inactiveColor: getF5F9FCColor(),
          onChanged: (SfRangeValues values) {
            setState(() {
              selectedStart = int.parse(moneyDoubleOrInt(
                  (_values.start).toDouble(),
                  postion: 0));
              selectedEnd = int.parse(moneyDoubleOrInt(
                  (_values.end).toDouble(),
                  postion: 0));

              // if (selectedEnd == selectedStart) {
              //   _values = const SfRangeValues(0, 1);
              // } else {
              _values = values;
              // }
            });
          },
        ),
      ),
    ],
  ),
),

這個(gè)是單滑塊的效果圖跟我們之前使用的 一樣,但是他的最小值定義完之后,就不是從0開始了,你給完最小值 就是初始階段,而不是可使用的最小值.我自定義的起始值就是0,然后在給一個(gè)最小值是顯示出來的,只可以在我給的最小值之間和最大值之間滑動(dòng)

Container(
  margin: EdgeInsets.only(
    left: SAdapt.width(10),
    right: SAdapt.width(10),
  ),
  child: Stack(
    children: [
      Positioned(
        // right: 21.w,
        left: 14.w,
        top: 19.w,
        child: Container(
          width: 12.w,
          height: 12.w,
          decoration: BoxDecoration(
            color: get826DD4Color(),
            borderRadius: BorderRadius.circular(10),
          ),
        ),
      ),
      Positioned(
        // right: 21.w,
        right: 14.w,
        top: 19.w,
        child: Container(
          width: 12.w,
          height: 12.w,
          decoration: BoxDecoration(
            color: getF5F9FCColor(),
            borderRadius: BorderRadius.circular(10),
          ),
        ),
      ),
      SfSliderTheme(
        data: SfSliderThemeData(
          //光暈顏色
          overlayColor: Colors.transparent,
          thumbColor: Colors.white,
          thumbRadius: 12,
          thumbStrokeWidth: SAdapt.width(2),
          thumbStrokeColor: get826DD4Color(),
          activeTrackHeight: SAdapt.width(2),
          inactiveTrackHeight: SAdapt.width(2),
          activeTrackColor: get826DD4Color(),
        ),
        child: SfSlider(
          min: 0.0,
          max: 10.0,
          value: sliderNum,
          interval: 20,
          minorTicksPerInterval: 1,
          inactiveColor: getF5F9FCColor(),
          onChanged: (newValue) {
            setState(() {
              sliderNum = newValue;
            });
          },
        ),
      ),
    ],
  ),
),
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末趁俊,一起剝皮案震驚了整個(gè)濱河市睹耐,隨后出現(xiàn)的幾起案子挎狸,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侧到,死亡現(xiàn)場離奇詭異勃教,居然都是意外死亡淤击,警方通過查閱死者的電腦和手機(jī)匠抗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來污抬,“玉大人汞贸,你說我怎么就攤上這事∮』” “怎么了矢腻?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長射赛。 經(jīng)常有香客問我多柑,道長,這世上最難降的妖魔是什么楣责? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任竣灌,我火速辦了婚禮,結(jié)果婚禮上秆麸,老公的妹妹穿的比我還像新娘初嘹。我一直安慰自己,他們只是感情好沮趣,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布屯烦。 她就那樣靜靜地躺著,像睡著了一般房铭。 火紅的嫁衣襯著肌膚如雪驻龟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天缸匪,我揣著相機(jī)與錄音翁狐,去河邊找鬼。 笑死豪嗽,一個(gè)胖子當(dāng)著我的面吹牛谴蔑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播龟梦,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼隐锭,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了计贰?” 一聲冷哼從身側(cè)響起钦睡,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎躁倒,沒想到半個(gè)月后荞怒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洒琢,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年褐桌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了衰抑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荧嵌,死狀恐怖呛踊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情啦撮,我是刑警寧澤谭网,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站赃春,受9級(jí)特大地震影響愉择,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜织中,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一锥涕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抠璃,春花似錦站楚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至采盒,卻和暖如春旧乞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背磅氨。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國打工尺栖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烦租。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓延赌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叉橱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挫以,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容