Never give up

Flutter - How to use exntension with getting widget position 본문

Flutter

Flutter - How to use exntension with getting widget position

대기만성 개발자 2021. 2. 7. 19:01
반응형

extension메소드의 공식문서를 보니

 

자주 사용하는 코드들을 구현해놓고 필요할 때 사용하면 편하겠다 라는 느낌을 받았습니다

(공식문서 : dart.dev/guides/language/extension-methods)

 

그래서 이번에는 Icon Button 클릭시 위젯의 위치값을

 

snackbar로 출력하는 예제를 만들어봤습니다

 

사용할 extension

extension PositionExtension on GlobalKey {
  Rect get getPosition {
    final RenderObject renderObject = currentContext?.findRenderObject();
    var translation = renderObject?.getTransformTo(null)?.getTranslation();
    if (translation != null && renderObject.paintBounds != null) {
      return renderObject.paintBounds
          .shift(Offset(translation.x, translation.y));
    } else {
      return null;
    }
  }
}

extension SnackBarExtension on GlobalKey<ScaffoldState> {
  ScaffoldFeatureController snackBar(String text) =>
      currentState.showSnackBar(SnackBar(content: Text(text)));
}

Main

class WidgetPosition extends StatelessWidget {
  final GlobalKey _buttonKey1 = GlobalKey();
  final GlobalKey _buttonKey2 = GlobalKey();
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        key: _scaffoldKey,
        appBar: AppBar(title: Text('Extension example')),
        body: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              IconButton(
                  key: _buttonKey1,
                  icon: Icon(Icons.looks_one),
                  onPressed: () {
                    Rect rect = _buttonKey1.getPosition;

                    _scaffoldKey.snackBar('rect : $rect');
                  }),
              IconButton(
                  key: _buttonKey2,
                  icon: Icon(Icons.looks_two),
                  onPressed: () {
                    Rect rect = _buttonKey2.getPosition;

                    _scaffoldKey.snackBar('rect : $rect');
                  })
            ]));
  }
}

(사실 이 예제에서는 scaffoldKey를 사용해야될 이유는 없지만 자주 사용하는 방식이기 때문에 한번 만들어봤습니다)

 

먼저 위젯의 위치를 찾는 방법으로 context.findRenderObject()를 사용하고

 

matrix값을 가져오기 위해 translation값을 사용합니다

 

getTransformTo 문서를 잠시 살펴보면

 

If `ancestor` is null, this method returns a matrix that maps from the local paint coordinate system to the coordinate system of the [PipelineOwner.rootNode]

 

ancestor값(필자가 넣은 null값)이 null일 때 matrix값을 반환해준다 정도로 축약해볼 수 있고

 

이 값에 getTranslation을 사용하면 Vector3값(x, y, z)을 얻을 수 있습니다

 

renderObject의 paintsBounds 문서를 살펴보면

 

These are also the bounds used by [showOnScreen] to make a [RenderObject] visible on screen.

 

이 경계는 showOnScreen으로 RenderObject를 화면에 보여주기 위해 사용된다 정도로 해석할 수 있습니다

 

이 값을 shift메소드를 사용하면 넣어준 Offset값에 따라 위치를 Rect값으로 반환해줍니다

 

rect값을 출력해보면 Rect.fromLTRB(0.0, 304.0, 411.4, 352.0)이런식으로

 

Left, Top, Right, Bottom좌표가 나와서 이 상태로 사용해도 되고 다른 값으로 변환해서 사용할 수 있습니다

 

여기 까지가 첫번째 extension에 대한 설명이었습니다..

 

두번째 extension은 우리가 자주(?) 사용하는 scaffoldKey를 이용한 snackbar를 extension으로

 

구현해 필요할 때 text만 넣어주면 되는식으로 구현을 해봤습니다

 

IconButton에 key.snackbar(string값)만 쓰면 되니 훨씬 더 간단해보이는 효과도 있고

 

여러군데에서 사용할 때 import해서 전역으로 사용하는것도 괜찮을거 같습니다

 

이 외에도 데이터 기본형으로도 extension을 사용해도 무방합니다

 

예를들어 간단한 사칙연산같은경우 이런식으로 표현해 볼 수 있습니다

extension Calculation on int {
  int addNum(int num1, int num2) => num1 + num2;

  int subNum(int num1, int num2) => num1 - num2;

  int multiNum(int num1, int num2) => num1 * num2;

  int divNum(int num1, int num2) => (num1 / num2).ceil();
}

//사용법은 아래와 같은식으로 사용하면 됩니다
//int result;
//result.addNum(1,2);

(아무도 사용하지 않겠지만요..)

 

요번 포스트는 아래 UI(Overlay entry)를 구현중에 생각나서 써본건데

 

문제가 조금 있어서 아래 위젯 소스는 공유하지 않기로 결정했습니다..

< 망작.gif >

 

반응형
Comments