iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0
Mobile Development

Flutter App 開發實戰系列 第 24

客製功能 DragTarget | 實作 [Day 24]

延續前面的文章,再了解了 DragTarget 的用法後,今天希望可以做出一個元件,draggableButton 在拖入 target 時能在 target 相應的位置中顯示按鈕,一個可以讓我們自訂按鈕位置的 Frame 。


我們需要找到一個 Widget 可以滿足我們的需求,可以任意擺放位置的元件, Stack 剛好可以達成,透過 children 屬性中添加 Positioned.fromRect

添加 Positioned.fromRect

在 stack 中添加兩個 Positioned 當作參考,這個範例中我們可以發現只要在 children 中添加元件就能符合我們的需求,能夠自訂位置

class Frame extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => FrameState() ;
}

class FrameState extends State<Frame> {
  @override
  Widget build(BuildContext context) {
    //定義兩個按鈕
    var draggableBtn1 = RaisedButton(child: Text("1"),onPressed: (){},);
    var draggableBtn2= RaisedButton(child: Text("2"),onPressed: (){},);
    return Stack(
      fit: StackFit.expand,//expand 會去符合父類別的大小
      children: <Widget>[
        Positioned.fill(child: Container(color: Colors.grey,)) ,
        Positioned.fromRect(
          rect: Rect.fromCenter(
              center: Offset(100 , 100) ,//決定中心點的位置
              width: 100 ,height: 100),
          child: draggableBtn1
        ),
        Positioned.fromRect(
            rect: Rect.fromCenter(
                center: Offset(210 , 100) ,
                width: 100 ,height: 100),
            child: draggableBtn2
        )
      ],
    ) ;
  }

}

範例圖示
https://ithelp.ithome.com.tw/upload/images/20200925/20130127D2XZ6QngVq.png

利用 DraggableInfo List 產生 children

修改一下上面的部分

class Frame extends StatefulWidget {
  Frame({
    Key key //增加 key 的傳入
  }):super(key:key) ; 

  @override
  State<StatefulWidget> createState() => FrameState() ;
}

class FrameState extends State<Frame> {
  final List<DraggableInfo> data = List(); //存放 DraggableInfo 的 list

  addData(DraggableInfo info) { //增加資料的方法
    if (!data.contains(info)) {
      data.add(info);
    }
  }

  @override
  Widget build(BuildContext context) {
  
    //利用 list generate 與 data 的資料來產生 children 
    List<Widget>  children = List.generate(data.length, (index) {
      var draggableBtn = RaisedButton(
          child: Text(data[index].text) ,
          onPressed: (){},
          );
      return Positioned.fromRect(
          rect: Rect.fromCenter(
              center: Offset(data[index].dx,data[index].dy),
              width: 100, height: 100),
          child: draggableBtn
      );
    });
    
    //設定背景
    children.insert(0,
        Positioned.fill(
            child: Container(
                color: Colors.grey,
            )
        )
    );

    return Stack(
      fit: StackFit.expand,
      children:children,
    ) ;
    
  }

}

新增一個顯示 target 的 StatefulWidget

GlobalKey<FrameState> _frameGlobalKey = GlobalKey();
DragTarget<DraggableInfo>(
    builder: (context,data,_){
        return Frame(key: _frameGlobalKey,) ;
    },
    onAccept: (data){
        setState(() {
            _frameGlobalKey.currentState.addData(data);
        });
    },
);

DraggableInfo 新增一個 setOffset 的方法

class DraggableInfo{
...
...
  setOffset(double dx, double dy) {
    this.dx = dx;
    this.dy = dy;
  }
..
}

DraggableButtonState 內修改

class DraggableButtonState extends State<DraggableButton>{
...
...
...
    var draggable = Draggable<DraggableInfo>(

      child: sizeBtn,
      feedback: Opacity(
        opacity: 0.5,
        child: sizeBtn
      ),
      childWhenDragging:sizeBtn,
      data: widget.data,
        onDragEnd: (detail){
        //當拖曳結束時修改 draggableIndo 內的 dx ,dy
         widget.data.setOffset(detail.offset.dx, detail.offset.dy);
        },
    );
    
    return draggable ;    
}    

圖示範例
https://ithelp.ithome.com.tw/upload/images/20200925/20130127OaOIVMeBZZ.png

完成後就能夠把按扭拖曳至frame中不過位子好像還不太正確,下一篇就來解決這個問題吧~


上一篇
客製功能 DragTarget | 範例 [Day 23]
下一篇
客製功能 DragTarget | 位置修正[Day 25]
系列文
Flutter App 開發實戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言