import 'dart:math';

import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart';

class ShakeAnimation extends StatefulWidget {
  @override
  _ShakeAnimationState createState() => _ShakeAnimationState();
}

class _ShakeAnimationState extends State<ShakeAnimation>
    with SingleTickerProviderStateMixin {
  AnimationController animationController;
  Animation<double> animation;

  @override
  void initState() {
    super.initState();
    animationController = AnimationController(
      vsync: this,
      duration: Duration(seconds: 5),
    )..addListener(() => setState(() {}));

    animation = Tween<double>(
      begin: 50.0,
      end: 120.0,
    ).animate(animationController);

    animationController.forward();
  }

  Vector3 _shake() {
    double progress = animationController.value;
    double offset = sin(progress * pi * 10.0);
    return Vector3(offset * 4, 0.0, 0.0);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Shake animation example")),
      body: Center(
        child: Transform(
          transform: Matrix4.translation(_shake()),
          child: FlutterLogo(
            size: 60.0,
          ),
        ),
      ),
    );
  }
}

'프로그래밍 > Flutter' 카테고리의 다른 글

Shared Preferences  (1) 2020.04.28
Cupertino ActionSheet  (0) 2020.04.05
flutter_staggered_grid_view  (0) 2020.03.15
Flutter Search-bar 구현  (0) 2020.03.13
플러터 - 크로스 플랫폼  (1) 2020.03.11

Use this package as a library

dependencies:
  flutter_staggered_grid_view: ^0.3.0
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';

 

staggered_grid_view

new StaggeredGridView.countBuilder(
  crossAxisCount: 4,
  itemCount: 8,
  itemBuilder: (BuildContext context, int index) => new Container(
      color: Colors.green,
      child: new Center(
        child: new CircleAvatar(
          backgroundColor: Colors.white,
          child: new Text('$index'),
        ),
      )),
  staggeredTileBuilder: (int index) =>
      new StaggeredTile.count(2, index.isEven ? 2 : 1),
  mainAxisSpacing: 4.0,
  crossAxisSpacing: 4.0,
)

crossAxisCount : 가로 타일의 길이이다. 위에서 확인했을 때 길이가 4임을 알 수 있다.

itemCount와 itemBuilder의 경우 일반적인 Builder와 사용법이 같다.

 

staggerdTileBuilder 에서 각 타일의 크기를 지정해줄 수 있는데,

위의 예시에서는 짝수인 경우 가로 세로 (2,2), 

홀수인 경우 (2,1)의 크기를 갖게 하였다.

 


 

'프로그래밍 > Flutter' 카테고리의 다른 글

Shared Preferences  (1) 2020.04.28
Cupertino ActionSheet  (0) 2020.04.05
image shake animation  (0) 2020.04.04
Flutter Search-bar 구현  (0) 2020.03.13
플러터 - 크로스 플랫폼  (1) 2020.03.11

검색 기능 구현

게시물을 검색하기 위한 Search-bar를 구현해보았다.

 

검색하고 싶은 값은 TextField 위젯을 사용했는데, 보통 컨트롤러로 입력 받은 값을 사용하지만, 나는 실시간으로 입력되는 글을 바로 바로

서버로 보내는 것을 하고 싶어서 onChanged() 를 사용했다. 

TextField(
              focusNode: _focus,
              keyboardType: TextInputType.text,
              onChanged: (text){
                _streamSearch.add(text);
              },
              decoration: InputDecoration(
                  hintText: lang(0),
                  border: InputBorder.none,
                  icon: Padding(
                      padding: EdgeInsets.only(left: 13),
                      child: Icon(Icons.search))),
            ),),

 

입력된 값은  _streamSeach 라는 미리 만들어둔 스트림 통로를 타고 String값이 이동하는데, 이 통로와 연결되어 있는

StreamBuilder가 통로에서 값을 받고 Node.js 서버에 전달한다.

StreamBuilder(
                   stream: _streamSearch.stream,
                   builder: (context,snapshot){
                     if(snapshot.hasData)
                      return FutureBuilder(
                        future: _fetchSearch(snapshot.data),
                        builder: (context,snaps){});
                        }
               )

Node.js 에서는 아래와 같이 값을 전달받아 데이터베이스에 쿼리를 날려 검색을 하도록 하였다.

    //--------------------------- 검색
   app.get('/search/:name',(req,res)=> {
    let sql = 'SELECT * FROM POSTS WHERE title REGEXP ?';
   let params =[req.params.name];
   connection.query(
        sql,params,
        (err, rows, fields) => {
            res.send(rows);
        }
      );
});

만약 검색으로 '일'을 검색하였다면 돌아온 응답 값은 아래와 같다.

[{"id":15,"title":"일본이 전자 산업 분야에서 내수시장을 방어하는 방법","content":"일반 재단법인 일본 원자력 문화 재단에서 인용\n일본 전기의 주파수는 시즈오카 현의 후지 천 당을 경계로 동쪽은 50Hz, 서일본이 60Hz와 다릅니다.","date":"2020-03-10T15:00:00.000Z","views":99,"good":30,"bad":60,"pic_thumb":"/image/1f71317100b29d5250f418db15a7c700","tag_0":"일본","tag_1":"전압","tag_2":"시즈오카","tag_3":null,"tag_4":null},
{"id":23,"title":"일류를 꿈꾸는 삼류 조폭의 이야기","content":"송강호란 배우의 이름을 확실히 사람들에게 각인시켜준 작품이었음. 이후로 송강호는 한국을 대표하는 배우로 성장했지","date":"2020-03-11T02:24:54.000Z","views":54,"good":30,"bad":21,"pic_thumb":"/image/36127119c67709878706cdae88ef15e4","tag_0":"영화","tag_1":"송강호","tag_2":"기생충","tag_3":"한국인","tag_4":null},
{"id":25,"title":"핵무기가 만들어지면 벌어지는 일들","content":"첫번째 이유는 우방국의 핵우산, 두번째는 박정희 정부때 찌라씨로 만들고 있었다가 완성 직전에 들켜서 npt에 가입한 걸로 알고 있음","date":"2020-03-10T15:00:00.000Z","views":75,"good":30,"bad":15,"pic_thumb":"/image/fcd451dba2f33e30da8133428448a36e","tag_0":"한국","tag_1":"핵무기","tag_2":"박정희","tag_3":"대한민국","tag_4":null},
{"id":36,"title":"80년대 일본을 느껴보자 감성 시티팝 플레이","content":"버블 경제 당시 최고의 음향장비와 굉장한 녹음시설 그리고 최고의 인력들이 다시는 만들지 못할 음악을 만들어냈다","date":"2020-03-11T05:43:39.000Z","views":0,"good":0,"bad":0,"pic_thumb":null,"tag_0":null,"tag_1":null,"tag_2":null,"tag_3":null,"tag_4":null}]

포스트의 '일'이라는 문자가 포함되어 있기 때문이다.

 

위에서 받아온 값은 JSON형식이기 때문에, 클라이언트단에서 받아 각 필드들을 읽고 맵핑하여 구조체 안에 넣는 작업을 했다.

class Post {
  final int postID;
  final String title;
  final String content;
  final String date;
  final String thumb;
  final int views;
  final int good;
  final int bad;
  Post(
      {this.postID,
      this.title,
      this.content,
      this.date,
      this.thumb,
      this.views,
      this.good,
      this.bad});

  factory Post.fromJSON(Map<String, dynamic> json) {
    return Post(
      postID: json['id'],
      title: json['title'],
      content: json['content'],
      date: json['date'],
      thumb: json['pic_thumb'],
      views: json['views'],
      good: json['good'],
      bad: json['bad'],
    );
  }
}

 

비동기식으로 이루어지는 것임으로 Future 로 캡슐화를 시켜두었다.

서버로부터 받은 값을 response 에 담아두고 위에서 설명한 맵핑 과정을 거친다.

  Future<List<Post>> _fetchSearch(String name) async {
    List<Post> _posts = [];
    final response = await http.get('http://127.0.0.1/search/'+name);
    final List<Post> parsedResponse = jsonDecode(response.body)
        .map<Post>((json) => Post.fromJSON(json))
        .toList();

    _posts.clear();
    _posts.addAll(parsedResponse);
    return _posts;
  }

위의 Future 식은 FutureBuilder와 연결하여 데이터를 다 받아왔을 경우 열려서 위젯을  return 하도록 설계하였다.

 

sidongmen

네트워크 기반의 어플은 서버로부터 데이터를 주고 받는 작업이 필수이다. 

플러터를 하면서 http와의 통신에 대해 공부를 많이 하고 있는데 그중에 스트림(Stream)과

비동기(Async) 프로그래밍의 매력을 크게 느끼고 있다.

이것을 잘 정리해 두어 후에 다른 앱을 개발할 때 두고 두고 응용해야겠다

 

_끗

'프로그래밍 > Flutter' 카테고리의 다른 글

Shared Preferences  (1) 2020.04.28
Cupertino ActionSheet  (0) 2020.04.05
image shake animation  (0) 2020.04.04
flutter_staggered_grid_view  (0) 2020.03.15
플러터 - 크로스 플랫폼  (1) 2020.03.11

크로스 플랫폼의 탄생

" 어플을 만들어보자! 라는 목표를 가진 시동맨이 있다고 하자. 시동맨은 이제 두가지를 떠올릴 것이다. 안드로이드 그리고 ios. 역시 ios보단 안드로이드가 쉬우니 안드로이드로 어플을 개발하기로 한다. 몇날 며칠 꼬박꼬박 밤을 새워 가며 짠! 하고 어플을 만들고 어플을 앱스토어에 올렸다. 어플의 성공을 기다리고 있던 얼마 후, 어플의 사용자인 김아무개는 '아이폰에는 없나요?' 라는 피드백을 올린다. 다섯 글자에 시동맨은 땀을 흘리기 시작한다. 그렇다. 이 어플은 안드로이드용 앱이기 때문에 아이폰에서는 쓸 수가 없는 것이다! 그래서 피드백을 반영해 똑같은 디자인과 똑같은 기능을 가진 아이폰용 어플을 Swift로 개발하기로 한다. 즉, 포팅(Porting)을 하기로 한다. 몇날 며칠 또 한번 꼬박꼬박 밤을 새워서 짠! ios용 어플을 개발하였다. 결국 어플을 하나 만드려고 각기 다른 언어로 싹 다시 만든 것이다! 심지어 ios용 어플을 개발하기 위해 거금을 들여 맥북까지 구입하게 되었다. 으악 :< 아니, 도대체 이 세상에는 한번의 코딩 작업으로 안드로이드 ios 환경에서 모두 실행 할 수 있는 뭐 그런 건 없는 것인가? "

 

플러터(Flutter)

구글(Google)에서 개발한 크로스 플팻폼, 플러터(Flutter)

  플러터는 구글에서 개발한 크로스 플랫폼 모바일 앱 개발 프레임워크이다. 구글에서 만들었으니 당연히 사용되는 언어 또한 구글에서 개발한 dart 라는 언어를 사용한다. 한번 dart로 작성한 것은 안드로이드와 ios 환경 양쪽에서 실행이 가능하다. (물론 ios 시뮬은 맥북이 있어야 하지만... 그래서 내가 맥북 질렀다 쓰바) 

 

  나는 2020년 1월 중반부터 이 플러터를 사용하기 시작하였는데, 플러터를 사용하면서 느낀 장점을 써보겠다.

지극히 내가 느낀 장점이니 굉장히 주관적이고, 아마 빠진 부분이 많을 것이다.

 

1. UI Rendering

  플러터에서는 기본적으로 각 플랫폼(Android, ios) 의 디자인을 그대로 제공한다. 즉, 안드로이드에서는 material 디자인과 ripple Animation 을,  ios에서는 cupertino 디자인을 볼 수 있다. 즉, 플랫폼에 따라 디자인 가이드에 맞게 화면을 그려주는 것이다. 이것은 마치 네이티브 언어로 작성한 것 같은 착각을 불러올 정도로 기분이 좋다. 또한 프로토타입의 UI 앱 화면 그대로를 구현하는 것도 자유자재로 할 수 있었다.

 

2. Fast development

  위에서 말했듯, 플러터는 dart라는 언어를 사용한다. 이전에 있었던 개발 경험(이라고 해도 거창한 게 아닌 대학교 과제)은 대부분 C언어나 자바로 개발하였다. 그래서 나는 새로운 언어인 dart를 배우는 데 어느정도 시간이 걸릴 것이라 생각했으나, 작은 어플을 하나 만드는 데 생각보다 오래 걸리지 않아서 놀랐다.

 

  플러터에서는 위젯(widget)이라는 것이 있는데, 이 것의 사용법, 작성 구조만 파악한다면 자바와 같은 객체지향 언어 개발 경험이 사람은 아마 해가 떠서 해가 지기 전까지는 충분히 배울 수 있을 것 같다. 플러터는 개발 속도가 빨랐는데, 그 이유는 dart언어가 배우기 쉽다는 것도 있지만 플러터에서 hot reload를 제공한다는 것이다.

 

실시간으로 작성된 코드가 반영된다.

  즉, 코드를 작성하거나 수정하면 그 즉시 에뮬레이터에서 실시간으로 바뀐 화면을 띄어준다. 덕분에 UI를 구현하는데 굉장히 간편했고 시간도 많이 절약할 수 있었다. (맥북에서는 VS Code로 개발 중인데 hot reload도 안되고 빌드도 안되서 실행은 Xcode에서 하는 중ㅜㅜ 아마도 안드로이드 스튜디오에서만 되는 듯.)

 

 

3. Flutter.dev, Youtube...etc

  구글에서는 정리하고 알려주는 걸 참 좋아하는 것 같다. 플러터로 어플을 개발하다가 구글링을 해야하는 순간이 오곤 하는데, 그럴 때마다 구글에 검색하면 거의 90퍼 이상은 해결된다. 도움이 되었던 사이트는

 

1. 스택오버플로우

 

Stack Overflow - Where Developers Learn, Share, & Build Careers

Stack Overflow | The World’s Largest Online Community for Developers

stackoverflow.com

  공식 홈페이지에서는 위젯이나 메소드의 자세한 설명과 예제를 제공한다. Yotube 계정에서는 '이 주의 위젯' 이라고 해서 매주 영상이 올라오는데, 한글 번역도 있어서 보는 재미가 쏠쏠하다.

2. 플러터 공식 홈페이지

 

Flutter - Beautiful native apps in record time

Flutter is Google's UI toolkit for crafting beautiful, natively compiled applications for mobile, web, and desktop from a single codebase. Flutter works with existing code, is used by developers and organizations around the world, and is free and open sour

flutter.dev

  나는 특히, 유투브로 많이 찾아 보았는데, 국내 유투버에서는 코딩파파(The Coding PaPa)님이 좋은 영상들을 올려주시는데 많은 도움을 받았다.

 

The Coding Papa 더코딩파파

한국의 IT산업의 미래를 위해!!

www.youtube.com

 

 

단점

  플러터는 단점 또한 분명히 있었는데, 플러터로 개발하다가 디자인 부분이 아니라, 기능적 측면에서 구현을 하다보면 내가 원하는 기능을 구현하려면 어쩔 수 없이 네이티브 언어를 써야할 때가 존재하게 된다... 특히, 까다로운 작업을 필요로 하는 어플인 경우에는 플랫폼의 의존성이 크기 때문에 더욱이 그럴 것이다.

 

  내 경우에는 휴대폰에서 갤러리 사진을 다중으로 선택하는 기능을 구현하는 것이였다. 사진 1개를 선택하는 기능 정도는 image_picker 라는 패키지를 사용하면 되었으나, 다중으로 선택하기 위해서 우선 갤러리에 있는 사진을 모두 gridview에 띄우려고 하였다. 그런데 용량이 큰 사진을 load 하면서 memory가 부족하게 되어 어플에 crush가 일어났다.

 

  그래서 구글로 찾아보다가 gridview에 띄울 때에는 원본 사진의 용량을 줄인 thumbnail 사진을 써야 한다는 것을 알게 되었다. 그렇게 어떻게 사진을 압축해서 저장할까 찾아보다가 안드로이드 MediaStore thumbnail 을 사용하기 위해 네이티브로 작성하여 channel을 만들고 플러터와 연결하는 노가다를 했다. 플랫폼에 맞게 해주는 작업 또한 추가적으로 생긴 것이다. '근데 이럴꺼면 애시당초에 플러터를 안쓰지' 라는 생각에 다른 패키지를 찾아보다가 다중 선택을 지원하는 multi_image_picker 을 찾아서 쓰게 되었다. 이 패키지를 뜯어서 썸네일을 생성하는 부분만 사용하려고 했으나, 이 패키지 또한 안드로이드와 ios에서 채널로 연결되어 있어서 그냥 그대로 사용했다...

 

  크로스 플랫폼에 대한 큰 기대를 하기는 아직 시대적으로 맞지 않나? 네이버 라인에서도 플러터를 이용해 어플을 만드려다가 결국 네이티브로 개발하였다라는 글이 있다. 여기

 

 

Flutter, 왜 선택하지 못했나 - LINE ENGINEERING

안녕하세요. LINE Biz+ Pay App Dev 팀에서 앱 클라이언트의 iOS 버전을 개발하고 있는 박혁준입니다. 저는 얼마 전 열렸던 LINE Developers Meetup에서 제가 발표했던 내용을 공유하려고 합니다. Flutter를 새로운 프로젝트에 사용해 보려고 조사했던 내용과 적용하려고 했던 이유, 그리고 적용하지 못했던 이유까지 한 번 짚어보겠습니다. 특히 Flutter에 대해 잘 모르거나 적용해 보면 어떨까 고민했던 분들에게 도움이 되었으

engineering.linecorp.com

 

(역시 네이티브 언어가 답인가...)

 

왼쪽부터 키자루, 아카이누, 아오키지이며 해군본부의 3대장이다.

  앱스토어에 들어가 보면 하루에도 수백개의 어플이 올라와 install 버튼을 눌러달라고 한다. 하지만 사람들이 쓰는 어플은 정해져 있다. 인스타그램, 페이스북, 카톡... 3대장이다 즉, 사람은 자신이 평소 사용하는 어플만 쓰지 새로운 어플을 다운받아서 써보는 일은 손에 꼽는다는 것이다.

 

  이런 현실 속에서 개발팀이 앱을 개발하면서는 굉장한 시간적, 금전적 비용이 들게 되는데, 플러터를 사용하게 되면 빠른 기간 내에 어플을 만들어 볼 수 있으며, 크로스 플랫폼이기 때문에 안드로이드, ios 두 가지를 개발하는 것 보다 비용 또한 줄어들게 된다. 위에서 말한 단점이 분명 존재하지만 총알의 갯수가 적은 스타트 업이나, 개인 개발자들에게 있어서는 좋은 프레임워크인 것 같다.

 

 

 

sidongmen

  나는 올해 초부터 취업용 포토폴리오를 위해 플러터를 이용해 Optio라는 앱을 만들고 있다. 이 어플이 이후에는 맥북을 샀으니 두고 두고 Swift를 공부하게 될 터이기에 플러터를 쓸 일이 없을 것 같지만, 현재 개발하고 있으니 중간 중간에 알게 된 내용을 블로그에 적어 기록해 두려고 한다.

 

_끗

 

 

 

'프로그래밍 > Flutter' 카테고리의 다른 글

Shared Preferences  (1) 2020.04.28
Cupertino ActionSheet  (0) 2020.04.05
image shake animation  (0) 2020.04.04
flutter_staggered_grid_view  (0) 2020.03.15
Flutter Search-bar 구현  (0) 2020.03.13

+ Recent posts