ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Flutter_17. GridView & Inkwell & FadeImage & Stack
    > Frontend/Flutter 2023. 5. 17. 17:35

     

     

     

    0) 학습 내용

    1. GridView & Navigator.push
    2. Inkwell & BoxDecoration
    3.  meals.dart setup
    4. FadeImage
    5. Stack & Positioned
    6. ModelItemTrait setup

     

     

    1) GridView & Navigator.push

    • Controls the layout of grid: default [top to bottom], [left to right ], [horizontally by 2 ]

    <categories.dart>

    body: GridView(
      padding: const EdgeInsets.all(24),
      // gridDelegate: controls the layout of Grid : top to bottom, left to right,  horizontally 2
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2, // Row 별 item 갯수
        childAspectRatio: 3 / 2, // item의 가로 세로 비율 => 3줄 가로 / 2줄 세로.
        crossAxisSpacing: 20, // Row item의 간격
        mainAxisSpacing: 20, // Colum item의 간격
      ),
      children: availableCategories  // dummy data
          .map((category) => CategoryGridItem(
              category: category,
              onSelectCategory: () {
                _selectCategory(context, category);
              }))
          .toList(),

     

    • 받은 dummy-category-item 하나당, CategoryItem 에 category-item 과 _selectCategory 함수를 보냄.

     

    void _selectCategory(BuildContext context, Category category) {
      final filteredMeals = dummyMeals
          .where((meal) => meal.categories.contains(category.id))
          .toList();
    
      // Navigator.push(context, route)
      Navigator.of(context).push(
        MaterialPageRoute(
            builder: (ctx) => MealsScreens(title: category.title, meals: filteredMeals)),
      );
    }

     

    • Navigator.push() 메소드를 통해 화면전환 가능.
    • MeaterialPageRoute( builder : (context) => 함께 보낼 내용 전달 )

     

    2) Inkwel && BoxDecoration in category_grid_item.dart

     

    <category_grid_item.dart >

    // component for single item
    import 'package:flutter/material.dart';
    import 'package:flutter08_meal/models/category.dart';
    
    class CategoryGridItem extends StatelessWidget {
      const CategoryGridItem({required this.category, super.key, required this.onSelectCategory});
    
      final Category category;
      final void Function() onSelectCategory;
      @override
      Widget build(BuildContext context) {
        // Inkwell: Event Listener with a Feedback
        return InkWell(
          onTap: onSelectCategory,
          splashColor: Theme.of(context).primaryColor, // visual tapping effect.
          borderRadius: BorderRadius.circular(16),
          child: Container(
            padding: const EdgeInsets.all(16),
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(16),
                gradient: LinearGradient(colors: [
                  category.color.withOpacity(.55),
                  category.color.withOpacity(.9),
                ], begin: Alignment.topLeft, end: Alignment.bottomRight)),
            child: Text(
              category.title,
              style: Theme.of(context)
                  .textTheme
                  .titleLarge!
                  .copyWith(color: Theme.of(context).colorScheme.onBackground),
            ),
          ),
        );
      }
    }
    

     

    • Inkwell : Container 와 같이 별도의  Event-Listener ? 적용할 수 있는 widget. 
    • splashColor : 탭시, 효과
    • BoxDecoration : 박스에 대한 꾸밈을 설정

     

     

     

     

     

    3) meals.dart Setup (화면 전환 )

     

    <meals.dart>

    import 'package:flutter/material.dart';
    import 'package:flutter08_meal/widgets/meal_item.dart';
    
    import '../models/meal.dart';
    
    class MealsScreens extends StatelessWidget {
      const MealsScreens({super.key, required this.title, required this.meals});
    
      final String title;
      final List<Meal> meals;
    
      @override
      Widget build(BuildContext context) {
        Widget content = ListView.builder(
            itemCount: meals.length,
            itemBuilder: (ctx, index) => MealItem(meal: meals[index]));
        if (meals.isEmpty) {
          content = Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  'No available Item',
                  style: Theme.of(context)
                      .textTheme
                      .headlineLarge!
                      .copyWith(color: Theme.of(context).colorScheme.onBackground),
                ),
                const SizedBox(height: 16),
                Text(
                  'Try Select a different category',
                  style: Theme.of(context)
                      .textTheme
                      .bodyLarge!
                      .copyWith(color: Theme.of(context).colorScheme.onBackground),
                )
              ],
            ),
          );
        }
        return Scaffold(appBar: AppBar(title: Text(title)), body: content);
      }
    }
    

     

    • 받은 meals 의 갯수가, 비어있지 않은 경우 meal_item && 비어있는 경우 비어있다고 알려줌.

     

     

     

    4)  FadeInImage in meal_item.dart

     

    import 'package:flutter/material.dart';
    import 'package:flutter08_meal/models/meal.dart';
    import 'package:flutter08_meal/widgets/meal_item_trait.dart';
    import 'package:transparent_image/transparent_image.dart';
    
    class MealItem extends StatelessWidget {
      const MealItem({super.key, required this.meal});
    
      final Meal meal;
    
      String get getComplexityText {
        return meal.complexity.name[0].toUpperCase() +
            meal.complexity.name.substring(1);
      }
      String get getAffordability {
        return meal.affordability.name[0].toUpperCase() +
            meal.affordability.name.substring(1);
      }
    
      @override
      Widget build(BuildContext context) {
        return Card(
          margin: const EdgeInsets.all(8),
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
          clipBehavior: Clip.hardEdge,
          //overflow: hidden
          elevation: 2,
          child: InkWell(
            onTap: () {},
            // stack: position multiple widgets above each other, but not above each other as column
            child: Stack(
              //stack ignores shape attribute.
              children: [
                // display an Image in fade.
                // flutter  pub add transparent_image
                FadeInImage(
                  placeholder: MemoryImage(kTransparentImage),
                  image: NetworkImage(meal.imageUrl),
                  fit: BoxFit.cover,
                  // fit
                  height: 200,
                  width: double.infinity,
                ),
                // Positioned widget: can give tlbr info to positioni the child.
                Positioned(
                  bottom: 0,
                  left: 0,
                  right: 0,
                  child: Container(
                    color: Colors.black54,
                    padding:
                        const EdgeInsets.symmetric(horizontal: 44, vertical: 5),
                    child: Column(
                      children: [
                        Text(
                          meal.title,
                          maxLines: 2,
                          textAlign: TextAlign.center,
                          softWrap: true,
                          overflow: TextOverflow.ellipsis,
                          style: const TextStyle(
                              fontSize: 20,
                              fontWeight: FontWeight.bold,
                              color: Colors.white),
                        ),
                        const SizedBox(height: 12),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            MealItemTrait(icon: Icons.schedule, label: '${meal.duration} min'),
                            const SizedBox(width: 12),
                            MealItemTrait(icon: Icons.work, label: getComplexityText),
                            const SizedBox(width: 12),
                            MealItemTrait(icon: Icons.work, label: getAffordability),
                          ],
                        )
                      ],
                    ),
                  ),
                )
              ],
            ),
          ),
        );
      }
    }
    

     

    • FadeInImage  =>
    • 온라인에서 이미지를 다운로드할 때, 일정 시간이 걸려서 아무것도 안보이는데, 올바르지 않음
    • 온라인에서 이미지를 다운로드할 때, 빈 칸이 보여지고, 이미지를 천천히 (fade-in) 해서 가져옴. 
    • Terminal:  flutter  pub add transparent_image 
    FadeInImage(
      placeholder: MemoryImage(kTransparentImage),
      image: NetworkImage(meal.imageUrl),
      fit: BoxFit.cover,
      // fit
      height: 200,
      width: double.infinity,
    ),

     

     

     

    5)  Stack & Positioned in meal_item.dart

     

     

     

     

    • Stack: Column 과 Row는 각각 세로, 가로 방향으로 순서대로 배치하지만, 겹쳐있듯이, 원하는 대로 배치할 경우 사용
    • Positioned: Stack은 단지 정해진 위치나 규칙 없이 위젯들을 배치하기에, 사용자가 직접 위치를 등록해야되는데, 이때 사용

     

    Positioned(
      bottom: 0,
      left: 0,
      right: 0,
      child: Container(
        color: Colors.black54,
        padding:
            const EdgeInsets.symmetric(horizontal: 44, vertical: 5),
        child: Column(
          children: [
            Text(
              meal.title,
              maxLines: 2,
              textAlign: TextAlign.center,
              softWrap: true,
              overflow: TextOverflow.ellipsis,
              style: const TextStyle(
                  fontSize: 20,
                  fontWeight: FontWeight.bold,
                  color: Colors.white),
            ),
            const SizedBox(height: 12),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                MealItemTrait(icon: Icons.schedule, label: '${meal.duration} min'),
                const SizedBox(width: 12),
                MealItemTrait(icon: Icons.work, label: getComplexityText),
                const SizedBox(width: 12),
                MealItemTrait(icon: Icons.work, label: getAffordability),
              ],
            )
          ],
        ),
      ),
    )

     

     

    https://velog.io/@sharveka_11/Positioned : 위치 파악

    • 여기서 positioned widget 의 위치 시작점은 Stack 안에 있는 FadeImage 기준으로 잡히게 된다.
    • 따라서, Positioned 의 값이 bottom: 0, left: 0, right: 0 이므로, FadeImage 기준으로 위치가 잡힘

     

     

     

    6) ModalItemTrait.dart Setup

     

    import 'package:flutter/material.dart';
    
    class MealItemTrait extends StatelessWidget {
      const MealItemTrait({super.key, required this.icon, required this.label});
    
      final IconData icon;
      final String label;
    
      @override
      Widget build(BuildContext context) {
        return Row(
          children: [
            Icon(
              icon,
              size: 17,
              color: Colors.white,
            ),
            const SizedBox(
              width: 6,
            ),
            Text(
              label,
              style: const TextStyle(color: Colors.white),
            )
          ],
        );
      }
    }
    

     

     

     

     

     

     

     

    댓글

Designed by Tistory.