23.03.14(Flutter)

MH S·2023년 3월 14일

Flutter

목록 보기
5/17

플러터 데이터 넘기기

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(

        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  // 상태 관리용 데이터가 아니다.
  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // 상태 -
  // 원래는 버튼 -> 로직이 실행돼서 -> 화면이 바뀐다.
  // State는 버튼 -> 값이 바뀌어서 -> 화면이 바귄다.
  // Test위젯 지우고 new Text위젯 넣기

  // State는 버튼 -> 값이 바뀌어서 -> 화면이 바뀐다.
  // Text 위젯에 State만 입력해두면
  // 개발자가 지우고 새로 넣지 않아도
  // 자동으로 갱신 된다.
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

예제1

import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home:Parent(),
    );
  }
}

class Parent extends StatefulWidget {
  const Parent({Key? key}) : super(key: key);

  
  State<Parent> createState() => _ParentState();
}

class _ParentState extends State<Parent> {
  // 2번 자식한테 줄 함수
  int count = 0;

  // 1번 자식한테 줄 함수
  void setCount(int newCount){
    setState(() {
      count = newCount;
    });
  }
  
  
  Widget build(BuildContext context) {
    return Row(
      children: [
        Child1(callback: setCount),
        Child2(count: count),
      ],
    );
  }
}
class Child1 extends StatelessWidget {
  final Function callback;

  const Child1({Key? key, required this.callback}) : super(key: key);

  
  Widget build(BuildContext context) {
    return ElevatedButton(
        onPressed: (){
          callback(Random().nextInt(100));
        },
        child: const Text("난수 생성"),
    );
  }
}

class Child2 extends StatelessWidget {
  final int count;
  const Child2({Key? key, required this.count}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Text(count.toString());
  }
}

예제 2(dart, java Stream)

Futer - 자스 promise 와 비슷
promise.then()
Iterable - 나열할 수 있는 것
list / set / map 등

<자바에서의 Stream>

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collector;
import java.util.stream.Collectors;

class Temp {
    public static void main(String[] args) {
        // Stream
        List<String> list = List.of("jaybon", "sunny", "duck");
        // 리스트에 u가 포함됨 문자열만 추출해서 리스트로 변환
        List<String> result1 = new ArrayList<>();
        for (String str : list) {
            if (str.contains("u")) {
                result1.add(str);
            }
        }
        // 리스트 문자열에 @temp.com 을 붙여서 리스트로 반환
        List<String> result2 = new ArrayList<>();
        for (String str : result1) {
            result2.add(str + "@temp.com");
        }

        // Stream 방식
        // Stream 은 데이터의 흐름을 이용해서 작업을 한다.
        // Java에서 Stream 은 한꺼번에 처리된다.
        // .collect 등을 호출 했을 때
        // 보기가 쉽다.
        // 함수형 프로그래밍을 이용할 수 있다.
        List<String> collect = list.stream()
             .filter(str -> str.contains("u"))
             .map(str -> str + "@temp.com")
             .collect(Collectors.toList());
    }
}

자바와 dart 스트림의 차이점

자바 Stream

  • 자바 Collections를 가공할 때 사용.
  • 한꺼번에 처리된다.

다트 Stream

  • 비동기 데이터를 처리할 때 사용
  • 언제 들어올 지 모를 데이터.
  • 실시간 데이터가 들어올 때마다 처리된다.

<main.dart>

import 'package:flutter/material.dart';
import 'package:flutter_stream_counter/counter_controller.dart';

void main(){
  runApp(CounterApp());
}

class CounterApp extends StatelessWidget {
  const CounterApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterPage(),
    );
  }
}

class CounterPage extends StatelessWidget {
  const CounterPage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    final counterController = CounterController();

    return StreamBuilder<int>(
      stream: counterController.counterStream,
      builder: (context, snapshot) {
        return Scaffold(
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              var nowCount = snapshot.data?? 0;
              counterController.addCount(nowCount + 1);
            },
          ),
          body: SafeArea(
            child: Center(
              child: Text(
                "${snapshot.data ?? "0"}",
                style: TextStyle(fontSize: 50),),
             ),
          ),
        );
      }
    );
  }
}

<counter_controller.dart>

// counter_controller.dart

import 'dart:async';

class CounterController{
  final _counterStreamController = StreamController<int>();

  Stream<int> get counterStream => _counterStreamController.stream;

  void addCount(int newCount){
    _counterStreamController.sink.add(newCount);
  }
}

상태관리 라이브러리

bloc/cubit
riverpod
getx - 상태관리/페이지이동/창띄우기/통신
provider - 전역 상태 관리(페이지 넘어갈시 데이터 보존)
: 위젯 간의 데이터 전달이 쉽다.
: 로그인 / 테마
hooks - 개별 위젯 상태 관리
: 리액트의 함수형 컴포넌트의 상태관리 기능이다.
: flutter_hooks는 리액트의 hooks를 따라 만들었다.

https://pub.dev/packages?sort=like

provider

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

void main(){
  runApp(CounterApp());
}

class CounterApp extends StatelessWidget {
  const CounterApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp (
      home: CounterPage()
    );
  }
}

class CounterPage extends HookWidget {
  const CounterPage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    // hooks는 무조건 build 밑에 만들기
    final counter = useState<int>(0);

    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          counter.value++;
        },
      ),
      body: SafeArea(
        child: Center(
          child: Text(
            "${counter.value}",
            style: const TextStyle(fontSize: 50),
          ),
        ),
      ),
    );
  }
}

상태가 변하면 위젯의 build 함수가 실행된다.
use 시리즈는 데이터가 유지됨.

  • useState - 상태 저장
  • useEffect - 화면이 빌드 된 후 작동해야할 것들을 작성
  • useRef - 상태관리는 필요없는데 데이터는 유지 되어야 하는 것들 저장 (화면이 재빌드가 되지않아 앱의 성능 측면에서 좋음)

밑의 두가지는 잘쓰이지 않음.

useCallback - 함수를 저장
useMemoized - 상태를 가공해서 저장

counter_controller

<main.dart>

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_stateful_1/counter_controller.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CounterController()),
      ],
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home:Parent(),
    );
  }
}

class Parent extends StatefulWidget {
  const Parent({Key? key}) : super(key: key);

  
  State<Parent> createState() => _ParentState();
}

class _ParentState extends State<Parent> {
  // 2번 자식한테 줄 함수
  int count = 0;

  // 1번 자식한테 줄 함수
  void setCount(int newCount){
    setState(() {
      count = newCount;
    });
  }

  
  Widget build(BuildContext context) {
    return Row(
      children: [
        Child1(callback: setCount),
        Child2(count: count),
      ],
    );
  }
}
class Child1 extends StatelessWidget {
  final Function callback;

  const Child1({Key? key, required this.callback}) : super(key: key);

  
  Widget build(BuildContext context) {
    final counterController = context.read<CounterController>();
    return ElevatedButton(
      onPressed: (){
        counterController.changeTo(Random().nextInt(100));
      },
      child: const Text("난수 생성"),
    );
  }
}

class Child2 extends StatelessWidget {
  final int count;
  const Child2({Key? key, required this.count}) : super(key: key);

  
  Widget build(BuildContext context) {
    final counterController = context.watch<CounterController>();
    return Text("${counterController.count}");
  }
}

<counter_controller.dart>

// counter_controller.dart

import 'package:flutter/cupertino.dart';

class CounterController with ChangeNotifier {
  int _count = 0; // _ 표시는 private

  int get count => _count;

  void changeTo(int newCount){
    _count = newCount;
    // 상태 변경 후 무조건 호출
    notifyListeners();
  }

}

0개의 댓글