반응형

[1.이미지(Image)] 이미지 관리

[2.컬러(Color)] 색상 관리

[3.텍스트스타일(TextStyle] 텍스트 스타일 관리

2편 컬러 사용법입니다.

이 글을 쓸때 고민이 되었던 부분중 하나가 enum을 사용하여 관리하는 것이 좋을지 기존에 플루터에서 이미 사용하고 있는 방식으로 하는 것이 좋을지 무척 고민이 되었습니다.

이유는 color 부분은 딱히 enum으로 변경한다고 해서 큰 장점이 생긴다고 생각되지 않아서 였는데요. 그래서 간략히 flutter에서 Color 제공하고 있는 방식만 소개하고 넘어갈까 합니다.

 

 

Color color = ResColors.buttonBlue;

이런 방식은 이미 flutter에서도 이렇게 제공하고 있는 부분이 있죠? 이런 방식을 동일하게 사용하는 것입니다.

 

아래와 같이 상수로 컬러를 정의해서 사용하면 됩니다.

abstract class ResColors{

static const Color buttonBlue = Color.fromRGBO(0,0,255,1);

}

이렇게 어플리케이션에서 나만의 color pattern을 사용하는 것입니다.

[예제]

abstract class ResColors{
  static const transparent = Color.fromRGBO(0, 0, 0, 0);
  static const white = Color.fromRGBO(255, 255, 255, 1.0);
  static const black = Color.fromRGBO(0, 0, 0, 1.0);
  static const greenLight_50 = Color.fromRGBO(242, 251, 247, 1.0);
  static const greenLight_100 = Color.fromRGBO(233, 246, 237, 1.0);
  static const greenLight_100F = Color.fromRGBO(212, 229, 212, 1.0); //by karzia
  static const greenLight_500 = Color.fromRGBO(1, 183, 100, 1.0);
  static const greenLight_600 = Color.fromRGBO(25, 161, 77, 1.0);
  static const grayScaleL1 = Color.fromRGBO(247, 247, 247, 1.0);
  static const grayScaleL2 = Color.fromRGBO(244, 244, 244, 1.0);
  static const grayScaleL3 = Color.fromRGBO(238, 239, 241, 1.0);
  static const grayScaleL4 = Color.fromRGBO(237, 237, 237, 1.0);

 

그런데 왜 저는 컬러(Color)를 관리하려고 할까요?

이유는 간단한데요. 협업이 쉽기 때문입니다. 색상표(Color code)가 R,G,B, A 4가지 값을 각각 0~255  만큼 가지고 있는데, 숫자로 되어있습니다.

때문에 소스코드에서 어떤 색상이 어디에 사용되어있는지를 검색하기 쉽지 않습니다.

또 협업을 하게 되는 경우 다른 사람이 작성한 코드에서 컬러값을 찾기는 더 힘들죠.

디자인 가이드가 바뀌는 경우에는 더 많은 작업이 필요해 집니다.

 

예를 들자면, 위에 현재 confirm 버튼으로 사용하고 있는  색상이 RGBO(0,0,255,1) 인데 디자이너가 색상을 좀 옅게 바꾸고 싶어서  confirm 버튼으로 디자인 된곳을 모두 RGBO(100,100, 200,1) 로 변경한다고 합시다.

그러면 개발자들은 RGBO(0,0,255,1)로 된 곳을 모두 찾아서 변경 해야 합니다. 

간혹 빠진 곳이 생기겠죠? 또 개발자중 몇명은 아직 변경 사실을 모르고 있을 수도 있습니다. 그러면 어떤 화면은 적용이 늦어지겠죠.

 

만약 위에 설명드린것 처럼 ResColors와 같이 컬러 테이블을 관리하고 있다면 buttonBlue = Color.fromRGBO(255) 만  Color.fromRGBO(100,100,200,1)로 변경하면 어플리케이션 전체에서 색상을 찾아서 수정할 필요가 없어지겠죠.

 

그래서 보통 어플리케이션에서 사용하는 컬러를 상수나 enum으로 이름을 주고 관리를 하는 편입니다.

이렇게 하면 디자이너와 협업도 쉬워지는데요. 디자이너가 특정 요소의 색상을 바꾸고 싶을때 컬러테이블의 값도 같이 수정 해주고 개발자에게 알려주면, 개발자는 해당 컬러 테이블만 수정 하면 되거든요.

 

 

 

 

 

[1.이미지(Image)] 이미지 관리

[2.컬러(Color)] 색상 관리

[3.텍스트스타일(TextStyle] 텍스트 스타일 관리

반응형

플루터(Flutter)는 Dart 로 UI를 개발하기에 무척 편리한 프래임워크이죠.

실제로 플루터가 나오기 전까지 Dart 언어에 대해서 평가가 그리 좋지 않았지만, 플루터 이후에 평가가 완전히 뒤바뀌었죠.

 

제가 플루터로 어플리케이션을 개발하면서 쌓은 노하우중 하나가 어플리케이션 리소스를 enum으로 관리하는 것인데요.

어떤것인지 소개 드리겠습니다.

 

플루터로 UI를 꾸밀때, 기본적으로 필요한 요소들이 있는데요. 이미지, 컬러, 텍스트스타일, 레이아웃 등이 있죠.

이런것들을 관리하기 위해서 개발자 분들은 다양한 방법을 사용하고 있을텐데요.

 

저는 enum을 활용하는 방법을 소개하고자 합니다.

 

어떻게 enum으로 리소스를 관리하지? 라고 궁금증이 생기신 분들이 있을텐데요.

먼저 제가 왜 enum을 선호하는지 부터 알려드리겠습니다.

 

제가 프로그래밍을 하면서 리소스와 관련되서 종종 격었던 문제들이 있었습니다.

- 텍스트로 리소스를 정의하여 사용하는 경우, 오타로 특정 위치에서만 정상적으로 안나오는 상황

- 플리케이션 리소스를 정의하는 방법이 개발자 간에 서로 달라서 중복된 리소스를 사용하는 경우

- 필요 없다고 생각되는 리소스를 삭제해서 리소스가 안나오는 경우

- 혹시 사용되고 있을까봐 삭제하지 못한 리소스

 

주로 요런 문제들인데요. 아마 이런 문제들은 프로그래밍 언어와 상관없이 코딩을 하다보면 종종 격는 문제입니다.

 

Enum으로 리소스를 관리하게 되면 장점은,

- 컴파일시 (또는 editing시)에 에러를 바로 발견 할수 있다.

- 리소스 사용에 대한 검색이 쉽다.

 

단점은

- 리소스를 위해서 enum을 만들어야 하는 번거로움이 있다.

- 자칫 잘못 디자인 되면 사용이 복잡해진다.

 

저는 예전 경험으로 String을 enum으로 관리하여 유사한 문제점들을 줄였던 적이 있었는데, 이를 활용하여 "어떻게 하면 

코딩이 복잡하지 않고 리소스를 사용할 수 있을까?"에 대해서 고민하여 다음과 같은 방식을 만들게 되었습니다.

 

 

첫번째,

Container(child:Image.asset( ResImages.beast.path, width: 120) )

이미지 리소스를 ResImages.beast.path 이렇게 리소스를 사용하는 방법입니다.

위와 같이 사용하기 위해서는 이미지 리소스를 어떻게 정의할지 고민이 필요한데요. 저는 다음과 같은 방식으로 정의합니다.

enum ResImages{

  addDevice("beast.png"),
  battery("people.png"),
  check("dog.png"),
  dashDevLandS("cat.png"),
  dashDevProbeS("fox.png"),
}

현재는 에러가 발생할 것이고, 

이와같이 정의할 수 있게 하기 위해서는 생성자 (constructor)와 추가적인 내용이 필요합니다.

 

enum ResImages{

:

  final String name;
  const ResImages( this.name);
}

이렇게 하면 string을 enum 정의할때 사용 할 수 있게 됩니다.

다음으로 image path를 얻어오는 getter가 있으면 매우 편리해지겠죠?

 

  String get path => "assets/images/$name";

이렇게 enum에 getter를 추가해 줍니다.

 

이렇게 하면 ResImages.beast.path 로 리소스의 위치를 얻어올 수 있게 됩니다.

요즘 coding 환경( ide)가 좋아져서 ResImages. 까지만 치면 정의된 리소스를 모두 볼수 있으니 더더욱 좋죠.

getter는 필요에 따라서 다양하게 추가할 수 있겠죠? 작은 이미지를 따로 모아놔서 smallPath 를 추가한다던가, 에니메이션을 위해서 프래임을 나눠서 준비했다고 한다면 getFrame(int idx) 같은 식으로 말이죠.

 

최종 완성본은 다음과 같습니다.

enum ResImages{

  addDevice("beast.png"),
  battery("people.png"),
  check("dog.png"),
  dashDevLandS("cat.png"),
  dashDevProbeS("fox.png"),
    ;
  final String name;
  const ResImages( this.name);
  String get path => "assets/images/$name";
 
}

 

 

음, 여기서 고민이 되네요.

이미지, 텍스트 스타일, 컬러를 모두 블로그 한 페이지에 정리할지 아니면 나눠서 정리를 할지.....[10분 딜레이]..

스압을 피하기 위해서 나눠서 정리하기로 했습니다. ^^

 

추가로 관심있으시면 아래 링크 참조 부탁드립니다.

 

[1.이미지(Image)] 이미지 관리

[2.컬러(Color)] 색상 관리

[3.텍스트스타일(TextStyle] 텍스트 스타일 관리

 

반응형

RoundedContainer 

모서리가 둥근 container 는 종종 필요합니다.

Container(
            width: 100.0,
            height: 150.0,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.all(Radius.circular(8.0)),
              color: Colors.redAccent,
            ),
            child: [your widget]
)

 

 

RoundedCorners clipping tip.

Rounded container를 만들고 나서 padding 을 없게 꽉 채우게 되는 경우에 corner가  clipping이 안됩니다.

그럴때 ClipRRect를 사용해서 clipping 합니다.

ClipRRect(
  borderRadius: BorderRadius.circular(20), // Image border
  child: SizedBox.fromSize(
    size: Size.fromRadius(48), // Image radius
    child: Image.network('imageUrl', fit: BoxFit.cover),
  ),
)

 

 

https://stackoverflow.com/questions/51513429/how-to-do-rounded-corners-image-in-flutter

 

How to do Rounded Corners Image in Flutter

I am using Flutter to make a list of information about movies. Now I want the cover image on the left to be a rounded corners picture. I did the following, but it didn’t work. Thanks! getItem(...

stackoverflow.com

 

 

 

반응형

코딩을 하다보면,  사용자 형식의 데이타 구조를 소팅해서 사용해야 하는 경우가 있습니다.

dart 의 List나 map 같은 자료구조에 보면, sort라는 함수가 있는데요. 

이를 활용하면 쉽게 구할 수 있습니다.

 

가장 기본적인 형태는 다음과 같겠죠.

Data라는 class가 있는데 이를 timestamp 기준으로 sorting이 필요하다고 가정하여 sample code를 작성해봤습니다.

class Data{
  int timestamp; // timestamp 로 
  String s;
  Data(this.timestamp,this.s);
  toString(){
    return "$timestamp:$s";
  }
}

List<Data> datas=[
  Data(1,"heee"),
  Data(4,"yyy"),
  Data(2,"kkk"),
  Data(3,"hhph")
];

comp(Data a, Data b){
  return a.timestamp - b.timestamp;
}

void main() {
  datas.sort((a,b)=> comp(a,b));
  
  
  for(final d in datas){
  print("${d.toString()}");  
  }
  
  
}

 

또,

일반적으로 timestamp를 사용할때 DateTime 을 사용하는 경우가 많은데요.

이런 경우 DateTime의 millisecondsSinceEpoch 을 이용하면 쉽게 처리 할 수 있습니다.

DateTime을 사용하지 않고 millisecondsSinceEpoch로 timestamp를 사용하기도 하죠.

class Data{
  DateTime timestamp; // timestamp 로 
  String s;
  Data(this.timestamp,this.s);
  toString(){
    return "$timestamp:$s";
  }
}



List<Data> datas=[
  Data(DateTime.utc(2022,1,25),"heee"),
  Data(DateTime.utc(2022,2,10),"yyy"),
  Data(DateTime.utc(2022,1,5),"kkk"),
  Data(DateTime.utc(2022,4,1),"hhph")
];

comp(Data a, Data b){
  return a.timestamp.millisecondsSinceEpoch - b.timestamp.millisecondsSinceEpoch;
}

void main() {
  datas.sort((a,b)=> comp(a,b));
  
  
  for(final d in datas){
  print("${d.toString()}");  
  }
  
  
}

 

해피 코딩!!

 

반응형

application 에서 실행중에 사용자가 퍼미션을 허용해야만 동작하는 module들이 있습니다.
이를 위해서 잘 만들어진 어플리케이션들은 퍼미션을 허용하는 UI를 제공하게 됩니다.

flutter에서 기본적인 퍼미션 허용하는 UI를 제공하는 방법을 소개합니다.

permission_handler [https://pub.dev/packages/permission_handler]

flutter에 permission_handler 라는 package가 있는데, 이를 이용하면 매우 쉽게 퍼미션을 설정 할 수 있습니다.


순서
Flutter에서 각 기능에 대한 퍼미션 설정을 위해서는 몇가지 파일들을 수정해야 하는데요.
순서를 한번 따라가 보겠습니다.

1. android manifest 에서 필요한 퍼미션을 추가합니다.
[project] /app/profile/AndroidManifest.xml
파일 안을 살펴보면 아래와 같이 use-permission 부분들이 있습니다.
필요한 퍼미션을 이 파일에 추가합니다.
저는 FINE_LOCATION과 BT 관련 퍼미션이 필요해서 다음과 같이 추가 했습니다.

<uses-permission android:name="android.permission.INTERNET"/>
<!-- 추가한 퍼미션 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>



2. permission_handler를 flutter pub 설정 파일에 추가합니다.
[project]/pubspec.yaml
위 파일에 다음과 같이 추가합니다.
permission_handler의 version은 pub.dev 에서 확인하시면 됩니다.

permission_handler: ^10.2.0

그리고 pub get 하기

3. permission 요청 하기
자 이제 모든 준비가 끝났고, 필요한 시점에 퍼미션 요청을 하면 됩니다.
예를 들면 BT scan전에는 BT 퍼미션이 필요하겠죠? 그러면 BT scan 전에 BT 퍼미션을 요청하는 코드를 작성해서 넣으면 됩니다.
퍼미션을 요청 하는 방법은 사용자 편의성을 고려해서 적용하는게 좋겠죠?
매번 이렇게 필요한 기능을 수행할때 퍼미션을 요청 할 수도 있지만,
사용성을 해치지 않는다면, 앱 최초 실행후 전체 퍼미션을 요청하는 것도 하나의 방법입니다.

더 정교하게 permission 요청 로직을 작성할 수 도 있지만, 아래와 같이 간단한 퍼미션 요청 함수를 만들고,
widget build() 에서 호출해도 어플리케이션 동작에 영향을 주지 않을 겁니다.

아래 사용한 permission의 request() 함수는 이미 퍼미션이 있으면 아무것도 하지 않기 떄문입니다.
또 _permissionCheck() 함수는 async로 만들어 놨기 때문에 build 함수의 퍼포먼스에 영향을 주지 않습니다.
( 영향을 주기야 하겠죠~ ^^ 그러나 무시할 수 있을 만큼이란 의미로 받아들이면 좋겠습니다.)

  _permissionCheck() async{

    print("permission check");

    Map<Permission, PermissionStatus> status = await [
      Permission.locationWhenInUse,
      Permission.bluetooth,
      Permission.bluetoothConnect,
      Permission.bluetoothScan
    ].request();
  }
  
  
class DeviceControlPage extends GetView<DeviceController>{
  const DeviceControlPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Get.put(DeviceController());
    controller.prepare();

    _permissionCheck();
     :



    return Scaffold(
          resizeToAvoidBottomInset : false,
          body: Obx(()=>Column(
          ....
          );
  }



이상 완료!!!

즐거운 코딩 생황~

반응형

어플리케이션 구성시, named route 를 사용하면, 어플리케이션 구조를 좀더 단순화 할수 있습니다.
그러면 코드의 시인성( readability ) 도 좋아지겠죠?

app route를 사용 하는 방식도 여러가지가 있는데요.
그중에서 저는 아래와 같이 router를 따로 분리해서 사용하는 것을 선호 합니다.


app router의 page 구성


abstract class Routes{

  static const INITIAL = '/';
  static const DEVICE = '/device';
  static const MONITOR = '/monitor';
  static const SEARCH = '/search';
}


class AppPages {
  static final pages = [
    GetPage(
        name: Routes.INITIAL, page: () => const MainPage()),
    GetPage(
        name: Routes.DEVICE, page: () => const DeviceControlPage()),
    GetPage(
        name: Routes.MONITOR, page: () => const MonitorPage()),
    GetPage(
        name: Routes.SEARCH, page: () => const SearchPage()),
  ];
}
반응형

Windows 환경에서 flutter_blue 를 설치하려다 다음과 같은 에러가 발생했습니다.

 


\macos\Classes\FlutterBluePlugin.h' (OS Error: The client does not have the required privileges.

 

이 문제는 flutter_blue 가 설치 될때 , symbolic link ( soft link) 로 되어있는 파일을 접근 하려다 발생되는 에러 입니다.

linux , macos 의 경우에는 symbolic link가 실제 file처럼 접근이 가능하지만, windows에서는 단순 숏컷으로 동장하기 때문에 문제가 발생한것으로 보이는데요.

해결하기 위해서는 flutter_blue 배포자가 수정을 해줘야 하겠지만,우리는 임시로 해결법을 찾아야 합니다.


아래 과정을 통해서 임시로 해결할 수 있습니다.

 

 

Solution 2: It is working well. (I'm using this solution)

 

1. flutter_blue의 git 을 clone 또는 download 합니다. (https://github.com/pauldemarco/flutter_blue)

2. 다운받은 flutter_blue 을 [설치된 flutter sdk folder]\flutter\.pub-cache\hosted 폴더로 복사합니다.

3. 이름을 변경합니다.  flutter_blue -> flutter_blue-0.8.0

 

이렇게 해서 pub get을 다시 해보시면 잘 동작 할것입니다.

.pub_cache\hosted 가 cache 폴더로 plugin들을 설치할떄 여기에 cache를 남겨두기 떄문에 여기에 정상적으로 업데이트 해놓으면 pub get 동작이 정상적으로 동작합니다.

 

 

반응형

\macos\Classes\FlutterBluePlugin.h' (OS Error: The client does not have the required privileges.



Problem: flutter_blue has installation problem in windows.

 

 

Solution 2: It is working well. (I'm using this solution)

 

1. download flutter_blue from git (https://github.com/pauldemarco/flutter_blue)

2. move flutter_blue to [your flutter sdk folder]\flutter\.pub-cache\hosted folder.

3. change name flutter_blue -> flutter_blue-0.8.0

4. done

 

 

 

 


Solution 1: it's just first found out solution. unfortunately it just can avoid ONLY get pub error.(FAILED)
1. flutter pub get

==> error will be occurred.

[your flutter sdk folder]\flutter\.pub-cache\_temp\dir7d36fb45\macos\Classes\FlutterBluePlugin.h' (OS Error: 지정된 파일을 찾을 수 없습니다.
, errno = 2)

2. copy dir7d36fb45 to [your flutter sdk folder]\flutter\.pub-cache\hosted\pub.dartlang.org
3. change name dir7d36fb45 to flutter_blue-0.8.0
4. cd flutter_blue-0.8.0 (created by you)
5. create pubspec.yaml in flutter_blue-0.8.0 folder
6. fill below content in pubspec.yaml

name: flutter_blue
description:
  Flutter plugin for connecting and communicating with Bluetooth Low Energy devices,
  on Android and iOS
version: 0.8.0
homepage: https://github.com/pauldemarco/flutter_blue

environment:
  sdk: '>=2.12.0 <3.0.0'
  flutter: ">=1.12.13+hotfix.6"

dependencies:
  flutter:
    sdk: flutter
  convert: ^3.0.0
  protobuf: ^2.0.0
  rxdart: ^0.26.0
  collection: ^1.15.0
  meta: ^1.3.0

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  plugin:
    platforms:
      android:
        package: com.pauldemarco.flutter_blue
        pluginClass: FlutterBluePlugin
      ios:
        pluginClass: FlutterBluePlugin
      macos:
        pluginClass: FlutterBluePlugin

7. now you have done preparing flutter_blue  cache :)
8. lets do  flutter pub get   !!
maybe it will be worked.
I know it is a temporary solution. but I believe it will help you understand how to work pub get..

If you need new pubspec.yaml ,
you can find out in here : https://github.com/pauldemarco/flutter_blue/blob/master/pubspec.yaml

+ Recent posts