플러터는 크로스플랫폼을 지원한다.

따라서 플러터로 개발하다 보면

각 플랫폼에 맞게 처리를 해줘야하는 상황이 있다.

물론 한가지로 통일해 짜도 좋지만

디테일을 살리기 위해선 각자 처리해주는것이 좋다.

 

그렇다면 플러터에선 어떤식으로 플랫폼을 구분할 수 있을까?

방법은 간단하다.

 

dart:io 를 이용하면된다.

import 시켜준뒤

import 'dart:io' show Platform;

Platform.isAndroid
Platform.isFuchsia
Platform.isIOS
Platform.isLinux
Platform.isMacOS
Platform.isWindows

해당 데이터들은 bool 값을 가지고 있다.

따라서 동작 코드에 조건문을 걸어 사용하면된다.

if (GetPlatform.isIOS) {
  showCupertinoDialog(
    context: context,
    builder: (context) => CupertinoAlertDialog(
      title: const Text("Dialog Title"),
      content: const Text("This is my content"),
      actions: [
        CupertinoDialogAction(
          isDefaultAction: true,
          child: const Text("Yes"),
          onPressed: () => Get.back(),
        ),
        CupertinoDialogAction(
          child: const Text("No"),
          onPressed: () => Get.back(),
        )
      ],
    ),
  );
} else {
  showDialog(
      context: context,
      builder: (context) => AlertDialog(
            title: const Text("Dialog Title"),
            content:
                const Text("This is my content"),
            actions: [
              TextButton(
                child: const Text("Yes"),
                onPressed: () => Get.back(),
              ),
              TextButton(
                child: const Text("No"),
                onPressed: () => Get.back(),
              )
            ],
          ));
}

현재 만들고 있는 앱은 IOS와 Android 두가지만 타겟으로 하기떄문에 위와같이 간단하게만 짜줬다.

또 상태관리를 위해 Getx를 사용중인데 마침 또 이런것도 지원해 이용했다.

지난번 AlertDialog에 Hero를 적용시키려다 조금 부자연스러워 많은 고민끝에 드디어 해결했다..

이번에는 AlertDialog를 쓰지않고 페이지라우트를 이용해 다른페이지 Container에 Hero를 입혀줬다.

이때 주의해야할 점은

모든 배경들은 투명처리 해야되며

나와 같이 ListView를 사용한다면 해당 Index 값을 페이지로 넘겨줘야한다.

Hero는 1 대 1 연결이 원칙이다.

따라서 Hero tag의 값은 나 아니면 너 이렇게 1개의 쌍으로만 이루어져야한다.

 

앱에 필수 요소인 Text

사용자에게서 해당 Text 값을 받을땐

글자 수를 제한둬야한다는 주의사항이 있다.

 

예를들어 화면에 나타낼 수 있는 글자 수 는 10자라고 하자

그런데 사용자가 15자를 저장했다.

화면에는 당연히 overflow가 나타낼것이다.

Text가 더 노출되도록 영역을 키운다던지 Text 크기를 줄이거나 할것이지만

기기의 케이스가 너무 많아 표준화하기 어렵다.

 

화면에 나타낼 수 있는 글자 수는 기종마다 다를것이다.

화면이 큰 기종은 작은 화면의 기종보다 상대적으로 나타나는 글자 수가 많을 것이다.

 

따라서 제일 효과적인 방법은

영역을 제한두고 overflow가 나오면

다양한 효과로 방지하는것이다.

 

사용법은 간단하다.

Text(
'안녕하세요',
overflow:
    TextOverflow
        .ellipsis,
),

아래 overflow 붙혀주는것이다.

하지만 이렇게만 설정해도 오류가 뜰것이다.

왜냐하면...

overflow의 기준(영역)을 지정해주지 않았기 때문이다.

영역은 다양한 방법으로 지정 가능하나 나는 Expanded 위젯을 이용했다.

 

TextOverflow의 속성은

이렇게 있는데 직접 다 해보는게 좋을거같다.

 

 

 

 

 

추가로 글자 줄 갯수도 지정 가능하다.

Text(
'안녕하세요',
overflow:
    TextOverflow
        .ellipsis,
 maxLines: 1,       
),

바로 maxLines로 지정해줄 수 있다.

앱을 디자인 하다보면 빠질 수 없는것중에 하나가 바로 에니메이션이다.

직관적이면서 심플한 에니메이션 효과는 앱 사용자에게 몰입감 있는 경험을 준다고 생각한다.

 

이번에는 이러한 효과가 들어간 AnimatedContainer에 대해 알아보겠다.

AnimatedContainer(
	duration: const Duration(milliseconds: 500),
	width: bool ? 100 : 0,
	height: bool ? 100 : 0,
    curve: Curves.bounceIn,
	child: const Text("test"),
),

 

기본적인 사용 예시이다.

 

duration  - 에니메이션 효과의 가동 시간이다.

width, height - bool 의 값에 따라 100 -> 0 or 0 -> 100으로 사이즈가 변한다.

curve - 다양한 에니메이션 효과들을 볼 수 있다. 직접보고싶다면 오른쪽 깃헙 주소에 들어가면된다.

아래 코드는 내가 제작하고 있는 앱의 코드이다.

AnimatedContainer(
                    duration: const Duration(milliseconds: 500),
                    curve: Curves.easeInOutQuart,
                    height: taskcontroller.isAllday.value == false ? 110 : 0,
                    child: ClipRect(
                      child: Wrap(
                        children: [
                          Row(
                            children: [
                              Expanded(
                                child: Inputfield(
                                  title: '시작',
                                  hint: homecontroller.startTime.value,
                                  widget: IconButton(
                                    icon: Icon(
                                      Icons.timer,
                                      color: Mycolor().textwhite,
                                    ),
                                    onPressed: () async {
                                    },
                                  ),
                                ),
                              ),
                              const SizedBox(width: 20),
                              Expanded(
                                child: Inputfield(
                                  title: '종료',
                                  hint: homecontroller.endTime.value,
                                  widget: IconButton(
                                    icon: Icon(
                                      Icons.timer,
                                      color: Mycolor().textwhite,
                                    ),
                                    onPressed: () async {
                                
                                    },
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ],
                      ),
                    ),
                  ),

자식 위젯에 보면 ClipRect 와 Wrap으로 감싸준것을 볼 수 있는데.

이는 에니메이션 가동중 UI가 오버플로우 하지않게 방지해준다.

좌측이 적용하지 않았을떄이며 오른쪽이 적용했을때이다.

앱에 따라 다르겠지만

게임을 제외하고는 보통 세로로 사용할 것이다.

 

제작하고 있는 앱의 UI를 다그리고

혹시나해서 화면을 회전 시켰더니


오른쪽과 같이 레이아웃에 오류가 떴다..

해당 앱은 세로모드를 지원안해도 될꺼같아 화면회전을 막는 법에 대해 소개하겠다.

 

방법은 간단하다.

 

import 'package:flutter/services.dart';

해당 파일을 import 후

Widget build(BuildContext context)

이 안에 아래 코드를 추가해주면된다.

  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);

위 코드를 간단하게 설명하자면 화면을 고정시키는 것이다. 

 

portraitUp - 정방향

landscapeRight :정방향에서 시계 방향으로90도 회전한 형태

portraitDown :정방향에서 시계 방향으로 180도 회전한 형태

landscapeLeft : 정방향에서 시계 방향으로 270도 회전한 형태

 


개인 프로젝트를 새롭게 시작하고

구현중에 있다.

현재 UI는 다 그렸는데 이제 DB 작업만 남았다..

앱 개발자를 준비하면 프론트, 백 둘다 빡시게 준비해야되는건가,,,

어렵다,,

 

오늘은 오늘 구현중 알게된 신박한 기능하나 소개하려고한다.

나는 보통 GetX를 이용하여 상태관리를 하고 있는데

수 많은 Get의 기능중

snackbar 이다.

간단한 사용법은

    Get.snackbar("저장 실패", "빈칸 없이 채워주세요",
          colorText: Mycolor().snackbarText,
          snackPosition: SnackPosition.TOP,
          backgroundColor: Mycolor().snackbarBg,
          icon: const Icon(Icons.warning_amber));

이며 설명이 필요한 부분은 따로 없어보인다.

이렇게까지 구현하고 테스트 해봤는데

사진과 같이 버튼을 막누르면 그 횟수만큼 계속해서 창이 나온다는점이다.

이를 해결하기 위해선

isSnackbarOpen를 써주면 된다.

 if (Get.isSnackbarOpen) {
      } else {
        Get.snackbar("저장 실패", "빈칸 없이 채워주세요",
            colorText: Mycolor().snackbarText,
            snackPosition: SnackPosition.TOP,
            backgroundColor: Mycolor().snackbarBg,
            icon: const Icon(Icons.warning_amber));
      }

코드와 같이 If문을 한번 걸어 현재 snackbar가 떠있는 상황인지 확인후 기능을 수행하도록

바꿔주면 아래와같이 해결된 결과를 확인할 수 있다.

 

+ Recent posts