<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近有一個小需求:圖表支援區域性顯示,如下底部的區域選擇器支援
這樣當圖表的資料量過大,不宜全部展示時,可選擇的區域性展示就是個不錯的解決方案。由於一般的圖表庫沒有提供該功能,這裡自己通過繪製來實現以下,操作效果如下所示:
目前這個範圍選擇器已經發布到 pub
上了,名字是 chart_range_selector。大家可以通過依賴進行新增
dependencies: chart_range_selector: ^1.0.0
這個庫本身是作為獨立 UI
元件存在的,在拖拽過程中改變區域範圍時,會觸發回撥。使用者可以通過監聽來獲取當前區域的範圍。這裡的區域起止是以分率的形式給出的,也就是最左側是 0
最右側是 1
。如下的區域範圍是 0.26 ~ 0.72
。
ChartRangeSelector( height: 30, initStart: 0.4, initEnd: 0.6, onChartRangeChange: _onChartRangeChange, ), void _onChartRangeChange(double start, double end) { print("start:$start, end:$end"); }
封裝的元件名為: ChartRangeSelector
,提供瞭如下的一些設定引數:
設定項 | 型別 | 簡述 |
---|---|---|
initStart | double | 範圍啟始值 0~1 |
initEnd | double | 範圍終止值 0~1 |
height | double | 高度值 |
onChartRangeChange | OnChartRangeChange | 範圍變化回撥 |
bgStorkColor | Color | 背景線條顏色 |
bgFillColor | Color | 背景填充顏色 |
rangeColor | Color | 區域顏色 |
rangeActiveColor | Color | 區域啟用顏色 |
dragBoxColor | Color | 左右拖拽塊顏色 |
dragBoxActiveColor | Color | 左右拖拽塊啟用顏色 |
這個元件整體上是通過 ChartRangeSelectorPainter
繪製出來的,其實這些圖形都是挺規整的,繪製來說並不是什麼難事。
重點在於事件的處理,拖拽不同的部位需要處理不同的邏輯,還涉及對拖拽部位的校驗、高亮示意,對這塊的整合還是需要一定的功力的。
程式碼中通過 RangeData
可監聽物件為繪製提供必要的資料,其中 minGap
用於控制範圍的最小值,保證範圍不會過小。
另外定義了 OperationType
列舉表示操作,其中有四個元素,none
表示沒有拖拽的普通狀態;
dragHead
表示拖動起始塊,dragTail
表示拖動終止塊,dragZone
表示拖動範圍區域。
enum OperationType{ none, dragHead, dragTail, dragZone } class RangeData extends ChangeNotifier { double start; double end; double minGap; OperationType operationType=OperationType.none; RangeData({this.start = 0, this.end = 1,this.minGap=0.1}); //暫略相關方法... }
在元件構建中,通過 LayoutBuilder
獲取元件的約束資訊,從而獲得約束區域寬度最大值,也就是說元件區域的寬度值由使用者自行約束,該元件並不強制指定。
使用 SizedBox
限定畫板的高度,通過 CustomPaint
元件使用 ChartRangeSelectorPainter
進行繪製。
使用 GestureDetector
元件進行手勢互動監聽,這就是該元件整體上實現的思路。
可以看出,這個元件的核心就是 繪製
+ 手勢互動
。其中繪製比較簡單,就是根據 RangeData
資料和顏色設定畫些方塊而已,稍微困難一點的是對左右控制柄位置的計算。
另外,三個可拖拽物的啟用狀態是通過 RangeData#operationType
進行判斷的。
也就是說所有問題的焦點都集中在 手勢互動
中對 RangeData
資料的更新。如下是處理按下的邏輯,當觸電橫座標左右 10
邏輯畫素之內,表示啟用頭部。
如下 tag1
處通過 dragHead
方法更新 operationType
並觸發通知,這樣畫板繪製時就會啟用頭部塊,右側和中間的啟用同理。
---->[RangeData#dragHead]---- void dragHead(){ operationType=OperationType.dragHead; notifyListeners(); }
void _onPanDown(DragDownDetails details, double width) { double start = width * rangeData.start; double x = details.localPosition.dx; double end = width * rangeData.end; if (x >= start - 10 && x <= end + 10) { if ((start - details.localPosition.dx).abs() < 10) { rangeData.dragHead(); // tag1 return; } if ((end - details.localPosition.dx).abs() < 10) { rangeData.dragTail(); return; } rangeData.dragZone(); } }
對於拖手勢的處理,是比較複雜的。如下根據 operationType
進行不同的邏輯處理,比如當 dragHead
時,觸發 RangeData#moveHead
方法移動 start
值。這裡將具體地邏輯封裝在 RangeData
類中。
可以使程式碼更加簡潔明瞭,每個操作都有 bool
返回值用於校驗區域也沒有發生變化,比如拖拽到 0
時,繼續拖拽是會觸發事件的,此時返回 false
,避免無意義的 onChartRangeChange
回撥觸發。
void _onUpdate(DragUpdateDetails details, double width) { bool changed = false; if (rangeData.operationType == OperationType.dragHead) { changed = rangeData.moveHead(details.delta.dx / width); } if (rangeData.operationType == OperationType.dragTail) { changed = rangeData.moveTail(details.delta.dx / width); } if (rangeData.operationType == OperationType.dragZone) { changed = rangeData.move(details.delta.dx / width); } if (changed) widget.onChartRangeChange.call(rangeData.start, rangeData.end); }
如下是 RangeData#moveHead
的處理邏輯,_recordStart
用於記錄起始值,如果移動後未改變,返回 false
。表示不執行通知和觸發回撥。
---->[RangeData#moveHead]---- bool moveHead(double ds) { start += ds; start = start.clamp(0, end - minGap); if (start == _recordStart) return false; _recordStart = start; notifyListeners(); return true; }
下面是結合 charts_flutter
圖示庫實現的範圍顯示案例。其中核心點是 domainAxis
可以通過 NumericAxisSpec
來顯示某個範圍的資料,而 ChartRangeSelector
提供拽的互動操作來更新這個範圍,可謂相輔相成。
class RangeChartDemo extends StatefulWidget { const RangeChartDemo({Key? key}) : super(key: key); @override State<RangeChartDemo> createState() => _RangeChartDemoState(); } class _RangeChartDemoState extends State<RangeChartDemo> { List<ChartData> data = []; int start = 0; int end = 0; @override void initState() { super.initState(); data = randomDayData(count: 96); start = 0; end = (0.8 * data.length).toInt(); } Random random = Random(); List<ChartData> randomDayData({int count = 1440}) { return List.generate(count, (index) { int value = 50 + random.nextInt(200); return ChartData(index, value); }); } @override Widget build(BuildContext context) { List<charts.Series<ChartData, int>> seriesList = [ charts.Series<ChartData, int>( id: 'something', colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault, domainFn: (ChartData sales, _) => sales.index, measureFn: (ChartData sales, _) => sales.value, data: data, ) ]; return Column( children: [ Expanded( child: charts.LineChart(seriesList, animate: false, primaryMeasureAxis: const charts.NumericAxisSpec( tickProviderSpec: charts.BasicNumericTickProviderSpec(desiredTickCount: 5),), domainAxis: charts.NumericAxisSpec( viewport: charts.NumericExtents(start, end), )), ), const SizedBox( height: 10, ), SizedBox( width: 400, child: ChartRangeSelector( height: 30, initEnd: 0.5, initStart: 0.3, onChartRangeChange: (start, end) { this.start = (start * data.length).toInt(); this.end = (end * data.length).toInt(); setState(() {}); }), ), ], ); } } class ChartData { final int index; final int value; ChartData(this.index, this.value); }
以上就是UI 開源元件Flutter圖表範圍選擇器使用詳解的詳細內容,更多關於Flutter圖表範圍選擇器的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45