본문 바로가기
flutter/Widget of the Week

Flutter[플러터] / SelectableText 를 사용하여 선택되는 텍스트 구현하기 (복사 가능 글자, 카피) SelectableText (Flutter Widget of the Week)

by ch5c 2025. 6. 12.
반응형

SelectableText class

단일 스타일을 적용한 선택 가능한 텍스트입니다.

대신 SelectionArea 또는 SelectableRegion을 사용하는 것을 고려해 보세요. 이는 텍스트 위젯을 포함하되 이에 국한되지 않는 위젯 하위 트리에서 선택을 가능하게 합니다.

SelectableText 위젯 단일 스타일로 텍스트 문자열을 표시합니다. 레이아웃 제약 조건에 따라 문자열은 여러 줄에 걸쳐 표시되거나 모두 한 줄에 표시될 수 있습니다.

https://youtu.be/ZSU3ZXOs6hc

공식 문서 코드

 


폰에서 뉴스 기사나 그런 것을 볼 때 간혹 그 텍스트를 복사하려고 할 때가 생긴다. 그럴 때에는 텍스트를 꾹- 하고 누르면 선택이 되면서 복사할 수 있는 콘텍스트 메뉴(Context menu) 가 나오게 되는데 기본적으로 Flutter 에서 많이 사용하는 텍스트는 Text 위젯을 사용하여 추가 처리를 하지 않는 이상 상호작용이 불가능하다. 여기서 그러한 텍스트가 선택이 될 수 있도록 도와주는 위젯이 있는데 바로 SelectableText 이다.

이 SelectableText 위젯은 사용자가 텍스트를 선택(드래그)할 수 있도록 해주는 위젯이다. 기본적인 Text 위젯과 다르게 SelectableText 는 텍스트 복사 기능을 지원한다. 한번 알아보자.

하위 속성
속성명 타입 기본값 설명
data String? 표시할 텍스트 내용
textSpan TextSpan? 텍스트를 스타일링하여 표시할 때 사용하는 TextSpan 객체
focusNode FocusNode? 이 위젯의 포커스를 제어하는 노드
style TextStyle? 텍스트에 적용할 스타일
strutStyle StrutStyle? 텍스트 줄 높이를 설정하는 스타일
textAlign TextAlign? 텍스트의 정렬 방식
textDirection TextDirection? 텍스트의 방향
textScaler TextScaler? 텍스트 크기를 조정하는 객체
showCursor bool false 커서를 표시할지 여부
autofocus bool false 위젯이 자동으로 포커스를 받을지 여부
minLines int? 표시할 최소 줄 수
maxLines int? 표시할 최대 줄 수
cursorWidth double 2.0 커서의 너비
cursorHeight double? 커서의 높이
cursorRadius Radius? 커서의 모서리 반경
cursorColor Color? 커서의 색상
selectionHeightStyle ui.BoxHeightStyle tight 선택 영역의 높이 스타일
selectionWidthStyle ui.BoxWidthStyle tight 선택 영역의 너비 스타일
enableInteractiveSelection bool true 사용자가 텍스트를 상호작용적으로 선택할 수 있는지 여부
selectionControls TextSelectionControls? 선택 도구 컨트롤 설정
dragStartBehavior DragStartBehavior start 드래그 시작 동작 방식
onTap GestureTapCallback? 텍스트가 탭되었을 때 호출되는 콜백
scrollPhysics ScrollPhysics? 스크롤 물리 속성
scrollBehavior ScrollBehavior? 스크롤 동작 정의
semanticsLabel String? 접근성용 설명 텍스트
textHeightBehavior TextHeightBehavior? 텍스트 높이 동작 정의
textWidthBasis TextWidthBasis? 텍스트 너비 기준
onSelectionChanged SelectionChangedCallback? 텍스트 선택 상태가 변경될 때 호출되는 콜백
contextMenuBuilder EditableTextContextMenuBuilder? _defaultContextMenuBuilder 컨텍스트 메뉴를 빌드하는 함수
magnifierConfiguration TextMagnifierConfiguration? 텍스트 선택 시 확대경 설정

 

하위 속성이 꽤 많다만 걱정할 필요 없다. 막상 사용하는 건 별로 없으니까

사용하는 방법은 Text 위젯과 거의 90퍼센트(기능적인 부분) 똑같다고 보면 된다.

SelectableText(
  'Hello! How are you?',
  textAlign: TextAlign.center,
  style: TextStyle(fontWeight: FontWeight.bold),
)

 

자 일단 이게 끝인데 그냥 위젯 이름을 Text 로 바꿔도 아무 문제없을 것이다.

그래서 이 부분에 대해서는 굳이 설명할 필요는 없다고 생각하고 넘기겠다.

그렇다면 주목해야 할 부분은 어디에 있는가?

바로 선택 시 뜨게 되는 Context menu 에 있다고 할 수 있겠다.

기본적으로 선택 시 우리가 흔히 보는 그 디자인의 그 창이 나오게 된다.

근데 놀랍게도 이 콘텍스트 메뉴를 마음대로 조물딱 할 수 있다는 것인데 바로 contextMenuBuilder 를 사용하면 그것이 가능해지게 된다. 한번 공식 예제를 봐보자. (데스크탑일 시 그냥 우클릭으로 하면 바로 나온다.)

 

 

 

놀랍게도 커스텀으로 제작이 가능하다.

자신의 앱의 콘셉트를 맞추고 싶다거나 할 때 굉장히 유용하게 사용될 듯싶은데 위의 예제는 contextMenuBuilder 자체의 예제라 SelectableText 를 사용하지 않고 있다. 한번 이 위젯과 커스텀 위젯을 결합시켜 보도록 하겠다.

 

 

좀 하자가 있게 코드를 짜서 테스트크탑에서 잘 안 되는 것 같긴 한데 모바일에서는 잘 되니 넘어가주길 바란다.

자 암튼 이렇게 직접 커스텀으로 아이템을 넣어줄 수가 있는데 한번 사용법을 알아보자면

contextMenuBuilder: (BuildContext context, EditableTextState editableTextState) {
  final List<ContextMenuButtonItem> buttonItems = editableTextState.contextMenuButtonItems;
  return AdaptiveTextSelectionToolbar.buttonItems(
    anchors: editableTextState.contextMenuAnchors,
    buttonItems: [
      ...buttonItems,
      ContextMenuButtonItem(
        label: '커스텀 액션',
        onPressed: () {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('커스텀 액션이 실행되었습니다!')),
          );
        },
      ),
    ],
  );
},

현재 이 코드에서 먼저 contextMenuBuilder 를 먼저 봐보자.

contextMenuBuilder: (BuildContext context, EditableTextState editableTextState) {

당연하겠지만 contextMenuBuilder 는 사용자가 텍스트를 선택했을 때 호출이 되는 형식이다.

여기서 editableTextState 라는 인자값을 주는데 이걸로 메뉴 생성에 필요한 텍스트 상태 관리가 가능해지게 된다.

final List<ContextMenuButtonItem> buttonItems = editableTextState.contextMenuButtonItems;

 

buttonItems 라는 이름으로 무언갈 가져오고 있는데 바로 기본으로 제공되는 ContextMenu 버튼 아이템들을 가져오고 있는 것이다. 이것으로 복사, 잘라내기, 붙여 넣기 같은 아이템을 불러왔다.

이제 빌더함수니까 return 을 해줘야 하는데 AdaptiveTextSelectionToolbar 로 해줬다.

return AdaptiveTextSelectionToolbar.buttonItems(

 

이 AdaptiveTextSelectionToolbar 위젯은 플랫폼에 맞게 context menu toolbar 를 그려주는 위젯이 되겠다.

이 위젯의 필수 속성인 anchors 를 사용해야 하는데

anchors: editableTextState.contextMenuAnchors,

 

그냥 editableTextState.contextMenuAnchors 를 사용해 줘서 툴 바가 어디에 표시될지 결정해 줬다.

이제 아래에는 마찬기로 필수 속성인 buttonItems 를 사용하여 툴바에 넣을 아이템들을 표시해 줬다.

buttonItems: [
  ...buttonItems, // 위에서 만든 변수
  ContextMenuButtonItem( // 새 아이템
    label: '커스텀 액션',
    onPressed: () {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('커스텀 액션이 실행되었습니다!')),
      );
    },
  ),
],

일단 기본적인 디자인을 따르도록 완전한 커스텀이 아닌 ContextMenuButtonItem 을 사용하여서 쉽고 간편하게 아이템을 하나 더 추가해 주었다.

 

이렇게 SelectableText 위젯에 대해서 알아보았다마는 중간에 살짝 길이 새버린 것 같긴 하다. 하지만 뭐 애초에 선택되는 게 끝인 위젯인데 뭐가 더 있겠는가 암튼 도움이 되었길 바라며 마치겠다.

 

반응형