플러터 처음 빨리 시작하기~

Computer 비관심/Flutter|2021. 4. 23. 01:04
반응형

1. 폴더구조

플러터개발시작시 유튜버들이 많이 사용하는 폴더구조

 

2. 스타일에 사용될 상수 만들기

디자인과 관련된 상수를 가진 색상 클래스, 엘리먼트 형태관련 클래스를 만들어서 디자인을 쉽게 하기

 

3. 데이터 모델 만들기

사용할 데이터의 형태를 지정하기 위해 데이터 모델만들기

 

4. 실제 사용하거나 UI디자인/테스트를 위한 데이터 만들기

개발중 데이터를 제공할 파일을 만듬

 

5. 여러개의 스크린을 불러올 수 있는 스크린콜랙션파일 생성 (Optional)

 

6. 여러개의 위젯을 불러올 수 있는 위젯콜렉션파일 생성

 

7. 웹을 위한 반응형 위젯 만들기

 

8. 데이터 오브젝트나 오브젝트 리스트를 json으로 바꾸기

 

9. 스트링으로 된 Json을 리스트로 바꾸기

 

10. GetX로 상태관리

GetX를 통해 state를 관리

 

11. GetX List 읽고 쓰고 수정하고 지우기

 

기타 미분류

플러터 위젯에 대해

 

 

 

 

1. 폴더구조

- assets/icons -svg

- assets/images -png

-lib/controllers

-lib/models - xxx_model.dart

-lib/screens - xxx_screen.dart

-lib/services

-lib/widgets 

-lib/configs/palette.dart

 

 

2. 스타일에 사용될 상수 만들기

lib/configs/pallette.dart

공통으로 쓰일 칼러지정

class Palette {
	static const Color PrimaryColor = Color(0xFF473F97);
}

 

materialApp / GetMaterialApp의 theme 속성을 사용할시

 

 

theme: ThemeData(
  // 앱바의 배경색과 글자의 색과 형태를 설정
  appBarTheme: Const AppBarTheme(backgroundColor: Palette.background, title: TextStyle( color: Colors.white, fontSize: 18,)),
  // 배경색을 설정
  sccaffoldBackgroundColor: Palette.background,
  // The background color for major parts of the app (toolbars, tab bars, etc)
  primaryColor: Colors.white,
  //버튼 등 색상
  accentColor: Palette.green,
  iconTheme: const IconThemeData(color: colors.black),
  fontFamily: GoogleFonts.montserrat().fontFamily,
  textTheme: GoogleFonts.montserratTextTheme(),
),
home: 홈스크린으로 사용할 위젯

 

 

 

lib/configs/styles.dart

공통으로 쓰일 엘레멘트의 스타일 지정

class Styles {
	statics const buttonTextStyle = TextStyle(
     fontSize:16.0,
     fontWeight: FontWeight.w600);
    
    statics const ChartTextStyle = TextStyle(
     color:Clors.grey,
     fontSize:16.0,
     fontWeight: FontWeight.w500);
    
    statics const tapTextStyle = TextStyle(
     fontSize:16.0,
     fontWeight: FontWeight.w600);
}

 

or

 

lib/configs/consts.dart

const kTextColor = Color(0xFF535353);
const kTextLightColor = Color(0xFFACACAC);
const kDefaultPadding = 20.0;

 

 

3. 데이터 모델

lib/model/product.dart

class Product {
string a, b, c;
	product ({this.a, this.b, this.c})
}

 

Json로 클래스를 만들어주는 사이트 - 여기서 쉽게 데이터 모델을 만들 수 있다.

javiercbk.github.io/json_to_dart/

 

 

4. 실제 사용하거나 UI디자인/테스트를 위한 데이터 만들기

lib/data/data.dart

List<Map> categories = [{"name":"music","icon": Icons.music_note,} {...},{...}];


List<Product> icecreamProducts = [
Product(a:'a',c:'ass',b:'ddd'),
Product(a:'a',c:'ass',b:'ddd'),
Product(...),
Product(...),
Product(...),
];

List<Product> chocolateProducts = [
Product(a:'a',c:'ass',b:'ddd'),
Product(a:'a',c:'ass',b:'ddd'), 
Product(...)
];

 

 

5. 여러개의 스크린을 불러올 수 있는 스크린콜랙션파일 생성

lib/screens/screens.dart

스크린들을 불러오는데 사용

(Marcus Ng 유튜브 비디오 참조)

 

export 'bottom_nav_screen.dart';
export 'home_screen.dart';
export 'stats_screen.dart;

 

 

6.  여러개의 위젯을 불러올 수 있는 위젯콜렉션파일 생성

lib/widgets/widgets.dart

위젯 불러오는데 사용

(Marcus Ng 유튜브 비디오 참조)

 

 

7. 웹을 위한 반응형 위젯 만들기

lib/widgets/responsive.dart

import 'package:flutter/material.dart';

class Responsive extends StatelessWidget {
  final Widget mobile;
  final Widget tablet;
  final Widget desktop;
  Responsive({Key key, @requred this.mobile, this.tablet, @required this.desktop})
      : super(key: key);

  static bool isMobile(BuildContext context) => 
    MediaQuery.of(context).size.width < 800;
  
  static bool isTablet(BuildContext context) => 
    MediaQuery.of(context).size.width >= 800 &&
    MediaQuery.of(context).size.width < 1200;
    
  static bool isDesktop(BuildContext context) => 
    MediaQuery.of(context).size.width >= 1200;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraints) {
      if (constraints.maxWidth >= 1200) {
        return desktop;
      } else if (constraints.maxWidth >=800) {
        return tablet ?? mobile;
      } else {
       return mobile;
      }
    });
  }
}

 

 

8. 데이터 오브젝트나 오브젝트 리스트를 json으로 바꾸기

List<Product> dataList =[
Product(name:'Product A', price:3700),
Pproduct(name:'Product B', price:3800),
]

String jsonDataList = jsonEncode(dataList);

 

bezkoder.com/dart-flutter-convert-object-to-json-string/

 

 

9. 스트링으로 된 Json을 리스트로 바꾸기

List dataList = jsonDecode(jsonDataList);
dataList.map((data) => Stock.fromJson(data)).toList();

stackoverflow.com/questions/51053954/how-to-deserialize-a-list-of-objects-from-json-in-flutter

 

 

10. GetX로 상태관리

 


// 데이터를 받아와야 할때
class MyStocksCtr extends GetxController {
  List<dynamic> products = [].obs;
  @override
  void onInit() {
    products.assignAll(datas); // 이렇게 말고 asyn 함수를 만들어야 함
    super.onInit();
  }
}

 

class MyStockScreen extends StatelessWidget {
  final MyStocksCtr controller = Get.put(MyStocksCtr());
  
  ...
  
  
  
  child: Obx(() {
            return ListView.builder(
                 itemCount: controller.products.length,
                 itemBuilder: (context, index) {
                   final Stock stock = controller.products[index];
                   return CustomCard(stock: stock);
                  }
              );
            },
          ),

 

 

쓰기 controller.products.add(쓸객체)

지우기 controller.products.delete(지울엘리먼트)

인덱스로 지우기 controller.products.deleteAt(지울엘리멘트의 인덱스)

 

수정

위젯에서 리스트의 인덱스 받기 

인덱스가 있으면 에디팅컨트롤러의 텍스트에 기존 내용을 넣기 

controller.products[index].속성 = 에디팅컨트롤러의 수정된 내용

 

Get.back

Get.to(() => MyHomePage(title: '전달값')

 

 

 

- 플러터는 레고의 블럭을 껴서 만드는 방식과 비슷하게 만들어 진다. 그 블럭을 위젯이라고 하는데 그런 위젯을 직접만들거나 남들이 제공하는 위젯을 끼워넣는 방식으로 개발이 이루어진다. 이와 같은 플러터의 구성 때문에 위젯간의 데이터 전달(커뮤니케이션)이 개발에서 상당히 중요하다.

 

- 개발시 stateful위젯과 stateless 위젯을 상속하여 자신의 위젯을 만드는데 stateless는 변화되는 상태값을 가지고 있지 않지만 stateful 위젯은 변화되는 상태값을 가지고 있다.

 

stateless 위젯은 직접 위젯을 build 하는 메서드를 가지고 있으며 값은 생성자를 통해 전달받으며 변하지 않는다. 

 

stateful 위젯은 생성자를 통해 값을 전달 받지만 state를 관리하기 위해 state위젯을 상속한 클래스를 불러서 그 클래스의 값을 state로 한다. 그리고 그 스테이트위젯을 상속한 클래스는 build메서드를 가지고 있다. 

 

즉,

class Bird extends StatefulWidget {
  const Bird({
    Key? key,
    this.color = const Color(0xFFFFE306),
    this.child,
  }) : super(key: key);
  
  // 생성자를 통해 얻어올 값 
  final Color color;
  final Widget? child;
 
  // 스테이트를 가질 수 있는 객체를 실행
  _BirdState createState() => _BirdState();
}



class _BirdState extends State<Bird> {

  // 스테이트, 변할수 있는 값들
  double _size = 1.0;

  void grow() {
    setState(() { _size += 0.1; });
  }

  @override
  Widget build(BuildContext context) {
    // 여기에 변수를 사용하면 주로 UI와 관련된 변수 사용
    
    return Container(
      color: widget.color,
      transform: Matrix4.diagonal3Values(_size, _size, 1.0),
      child: widget.child,
    );
  }
}

 

 

 

UI를 개발시 기능은 미구현된 형태로 먼저 개발하면 편함

댓글()

[플러터] stateless 위젯에서 controller 사용하기

Computer 비관심/Flutter|2021. 4. 10. 21:54
반응형

stateful widget을 사용하면 편하긴 한데 stateless widget을 사용하여 컨트롤러를 등록하고 스코를의 위치를 얻어내려고 하였다. 보통은 공식문서에서도 적혀있듯 stateful widget을 사용한다.

 

class MyStockScreen extends StatelessWidget {
  final MyStocksCtr controller = Get.put(MyStocksCtr());
  final ScrollController scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    scrollController.addListener(() => print(scrollController.position.pixels));

    return Scaffold(
    ....

 

 

build 함수 안에 컨트롤러리스너를 등록한다.

dispose가 없는데 문제가 없는지 모르겠다.

stateless라 state자체가 없기 때문에 문제가 없다는거 같은데..

어째튼 작동은 한다.

댓글()

플러터에서 자식 위젯의 메서드 부모에서 호출하기

Computer 비관심/Flutter|2021. 4. 10. 01:12
반응형

플러터는 위젯으로 구성되어 있다. 그렇기 때문에 위젯간의 소통을 할 수 있는 방법을 아는 것이 중요하다. 위젯간의 소통 방법들을 공부하지 않으면 분리되지 않은 거대 위젯으로 앱이 구성이 될 것이다.

 

 

부모의 버튼을 눌렀을때 자식 스크롤 위젯이 자동으로 맨 밑까지 내려오게 하는 기능을 구현해야 했다.

위젯이 나누어지지 않았을 때는 문제가 없었지만 위젯이 부모와 자식으로 나누어 지면서 버튼과 리스트가 분리 되었다.

 

 

이때 부모가 자식의 메서드를 호출해서 그 메서드가 자식을 움직이게 만드려면 어떻게 해야 할까?

StackOverflow에서 두가지 방법을 찾을 수 있었다.

 

 

첫번째는 메서드를 초기화한 클레스의 인스턴트를 전달하는 방법

1. 클레스에 메서드를 초기화 해서 자식 위젯에 인스턴트를 전달한다.

2. 자식위젯에서 구현한 메서드를 전달받은 인스턴트의 메서드에 넣는다.

3. 부모에서 구현한 메서드를 호출한다.

(그러면 자식에서 구현한 메서드가 실행됨)

 

class HomePageController {
  void Function() methodA;
}

class MyApp extends StatelessWidget {

  final HomePageController myController = HomePageController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon: Icon(Icons.help),
            onPressed: () {
              myController.methodA();
            },
          ),// IconButton
        ),// AppBar
        body: HomePage(
          controller: myController,
        ),// HomePage
      ),
    );
  }
}

class HomePage extends StatefulWidget {

  final HomePageController controller;

  HomePage({ this.controller });

  @override
  _HomePageState createState() => _HomePageState(controller);
}

class _HomePageState extends State<HomePage> {

  _HomePageState(HomePageController _controller) {
    _controller.methodA = methodA;
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }

  void methodA() {}
}

 

 

 

두번째는 자식위젯에 글로벌키 넣어 접근하는 방법

1. 자식 위젯이 키를 전달 받을 수 있도록 만든다.

2. 자식 위젯에 글로벌 키를 만든뒤 자식에게 전달.

3. 만들어진 글로벌 키로 자식 메서드 접근

 

GlobalKey<_HomePageState> globalKey = GlobalKey();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon: Icon(Icons.help),
            onPressed: () {
             globalKey.currentState.methodA();
            },
          ),
        ),
        body: HomePage(key: globalKey),
      ),
    );
  }
}
class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }

  void methodA() {}
}

여기서 중요한건 위젯을 파일로 나누었을때 GlobalKey<_HomePageState> globalKey=GlobalKey()에서

_ (언더바) 를 사용하면 참조를 못 한다는 것이다. 

 

코드출처: stackoverflow.com/questions/53692798/flutter-calling-child-class-function-from-parent-class

댓글()

firebase SDK 없이 flutter에서 firestore에 post요청 보내기

Computer 비관심/Flutter|2020. 11. 26. 00:29
반응형

실시간 기능도 필요 없어서 SDK를 사용하고 싶지 않았다. 

그냥 간단하게 요청하여 필요한 데이터를 json현태로 받고 싶었다. 그런데 flutter 자료가 아직 많지 않아서 해맷다.

 

 

1. 일단 http 요청을 하기위해서 http모듈을 임포트 하였다.

import 'package:http/http.dart' as http;

 

2. 아래와 같이 GET 요청을 보내게 되면 모든 documents를 불러오게 된다. 

https://firestore.googleapis.com/v1/projects/프로젝트명/databases/(default)/documents

 

다큐먼트를 모두 불러온 뒤 클라이언트에서 필터링하면 시간도 엄청나게 걸릴 뿐더러 차후 과금에 문제가 생긴다.

 

3. 파이어베이스의 structuredQuery를 사용하면 데이터를 반환받는 조건을 만들어서 보낼 수 있다.

cloud.google.com/firestore/docs/reference/rest/v1/StructuredQuery

 

아래는 이름을 검색해서 그 검색한 이름과 동일한 다큐먼트를 반환 하는 스트럭쳐드쿼리 예제이다.

1) projectID는 firestore의 프로젝트 이름

2) col은 colection이름

3) fielVal은 내가 찾을 값 (name 필드에서 value가 찾을 내용과 같은 다큐먼트를 필터해서 리턴)

4) body에 json.encode를 해야함.

dynamic response = await http.post(
  'https://firestore.googleapis.com/v1/projects/' +
  	projectID +'/databases/(default)/documents:runQuery',
  headers: {'Content-Type': 'application/json'},
  body: json.encode({
  	'structuredQuery': {
  		'where': {
  			'fieldFilter': {
  				'field': {'fieldPath': 'name'},
  				'op': 'EQUAL',
  				'value': {'stringValue': '${fielVal}'}
 				}
              },
              'from': {'collectionId': '${col}'}
              }
}));

 

 

댓글()

파이썬으로 이미지 다운로드 하기

Computer 비관심/PyQt5|2020. 11. 10. 12:31
반응형

파이썬으로 이미지를 다운받으면 반복적인 이미지 다운로드 작업을 자동화 할 수 있다.

이 코드는 단순히 다운로드 하는 작업만 진행하지만 selenium이나 requests를 잘 섞어서 사용하면 자동으로 특정한 페이지의 이미지들을 다운 받을 수 있도록 만들 수 있다.

## 필요한 모듈을 불러온다.
import requests # to get image from the web
import shutil # to save it locally

## 다운로드할 이미지 URL
image_url = "http://~~~~.jpg"
filename = image_url.split("/")[-1]

# 스트림으로 이미지 얻어옴
r = requests.get(image_url, stream = True)

# 이미지가 잘 받아졌는지 확인
if r.status_code == 200:
    # 디코드 컨텐츠를 True로 세팅, 그렇지 않으면 파일 사이즈가 0
    r.raw.decode_content = True
    
    # 바이너리로 쓰기 권한으로 저장
    with open(filename,'wb') as f:
        shutil.copyfileobj(r.raw, f)
        
    print('Image sucessfully Downloaded: ',filename)
else:
    print('Image Couldn\'t be retreived')

댓글()

플러터에서 firebase_auth와 flask 서버 같이 사용하기.

Computer 비관심/Flutter|2020. 11. 7. 00:33
반응형

이렇게 사용하면 아래와 같은 장점이 있을 것 같다.

1. 사용자 개인정보를 직접 저장하고 있지 않아도 된다.

 - 개인정보의 보안이나 관리가 어렵다. 

2. 서버에서 구현하기 귀찮은 모바일확인, 페이스북&구글로그인 등을 쉽게 구현 가능하다.

3. firestore의 단점인 과금 문제를 보완 가능. - 정말 필요한 채팅서비스에서만 firestore를 사용하면 될듯. 나머지는 flask SQL서버에 저장.

4. 파이썬을 서버로 사용하기 때문에 데이터처리에도 유용하지 않을까.....?

 

플러터에서 

1. firebaseAuth로 로그인을 함

2. firebaseAuth로 아이디 토큰을 받음

3. http post로 토큰을 서버로 보냄.

 

서버에서

1. post로 온 토큰을 firebase의 

    decoded_token = auth.verify_id_token(id_token)

    uid = decoded_token['uid'] 사용해서 유저를 확인한다.

 

 

로컬호스트에서 진행 했기 때문에 실제 서비스를 하면

어떤 문제가 생기는지는 모르겠다. 

모바일 기기에서 http post를 보낼때 localhost라고 적으면 모바일이 ip를 알지 못하니

ipconfig에 들어가서 실제 로컬호스트 아이디를 입력해줘야 한다.

 

 

댓글()

파이어베이스 로그인

Computer 비관심/Flutter|2020. 11. 6. 01:58
반응형

 

 

firebase_auth 를 사용하려던중 문제 발생

stackoverflow.com/questions/63492211/no-firebase-app-default-has-been-created-call-firebase-initializeapp-in

 

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

위와 같은 방법으로 문제 해결

댓글()

플러터 스트럭처 만들기 작성중

Computer 비관심/Flutter|2020. 11. 3. 23:35
반응형

github.com/infocentre/flutternewproject

 

lib안에 폴더는 

core

 /models

 /services

 /viewmodels - changeNotifier

   .base_model = viewmodel에서 중복되는 boilerplate를 옮김

ui

 /shared - 공유하는 사용자 정의의 디자인 속성을 사용하기 위해

 /views

 /widget

 .router

 

 

MVVM관련 폴더와 ui폴더로 나눈다.

 

provider

댓글()