ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Flutter 플러터] 인스타그램 앱 따라 만들기
    Study/Flutter, Dart 2024. 9. 12. 18:05
    728x90
    반응형

    인스타그램 앱 따라 만들기

     

     

    main.dart

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:google_fonts/google_fonts.dart';
    
    import 'body.dart';
    
    void main() {
      runApp(const InstaCloneApp());
    }
    
    class InstaCloneApp extends StatelessWidget {
      const InstaCloneApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(
              colorScheme: const ColorScheme.light(
                  primary: Colors.white, secondary: Colors.black),
              bottomNavigationBarTheme: const BottomNavigationBarThemeData(
                showSelectedLabels: false,
                showUnselectedLabels: false,
                selectedItemColor: Colors.black
              ),
              useMaterial3: true),
          home: InstaCloneHome(),
        );
      }
    }
    
    class InstaCloneHome extends StatefulWidget {
      const InstaCloneHome({super.key});
    
      @override
      State<InstaCloneHome> createState() => _InstaCloneHomeState();
    }
    
    class _InstaCloneHomeState extends State<InstaCloneHome> {
      late int index;
    
    
      @override
      void initState() {
        super.initState();
        index = 0;
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: index == 0 ?AppBar(
            title: Text(
              'Instagram',
              style: GoogleFonts.lobsterTwo(color: Colors.black, fontSize: 32),
            ),
            centerTitle: false,
            actions: [
              IconButton(
                icon: const Icon(Icons.favorite_outline, size: 32,),
                onPressed: () {
                  print('Tab favorite');
                },
              ),
              IconButton(
                icon: const Icon(CupertinoIcons.paperplane, size: 32,),
                onPressed: () {
                  print('Teb paperplane');
                },
              )
            ],
          ) : null,
          body: InstaBody(index: index),
          bottomNavigationBar: BottomNavigationBar(
            currentIndex: index,
            onTap: (newIndex) => setState(() => index = newIndex),
            items: const [
              BottomNavigationBarItem(icon: Icon(Icons.home, size: 28,), label: 'Home'),
              BottomNavigationBarItem(icon: Icon(Icons.search, size: 28,), label: 'Search'),
            ],
          ),
        );
      }
    }

     

     

     

    body.dart

    import 'package:flutter/material.dart';
    import 'package:insta_clone/screen/home_screen.dart';
    import 'package:insta_clone/screen/search_screen.dart';
    
    class InstaBody extends StatelessWidget {
      final int index;
    
      const InstaBody({required this.index, super.key});
    
    
      @override
      Widget build(BuildContext context) {
        if (index == 0) {
          return const HomeScreen();
        }
    
        return const SearchScreen();
      }
    }
    반응형

     

     

    home_screen.dart

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    
    class HomeScreen extends StatelessWidget {
      const HomeScreen({super.key});
    
      @override
      Widget build(BuildContext context) {
        return const SingleChildScrollView(
          child: Column(
            children: [
              StoryArea(),
              FeedList() 
            ],
          ),
        );
      }
    }
    
    class StoryArea extends StatelessWidget {
      const StoryArea({super.key});
    
      @override
      Widget build(BuildContext context) {
        return SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Row(
            children: List.generate(10, (index) => UserStory(userName: 'User $index')),
          ),
        );
      }
    }
    
    class UserStory extends StatelessWidget {
      final String userName;
      
      const UserStory({
        required this.userName,
        super.key,
      });
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 12),
          child: Column(
            children: [
              Container(
                width: 80,
                height: 80,
                margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
                decoration: BoxDecoration(
                  color: Colors.blue.shade300,
                  borderRadius: BorderRadius.circular(40)
                ),
              ),
              Text(userName),
            ],
          ),
        );
      }
    }
    
    class FeedData {
      final String userName;
      final int likeCount;
      final String content;
    
      FeedData({required this.userName, required this.likeCount, required this.content});
    }
    
    final feedDataList = [
      FeedData(userName: 'User 1', likeCount: 50, content: '오늘 점심은 맛있었다'),
      FeedData(userName: 'User 2', likeCount: 20, content: '오늘 아침은 맛있었다'),
      FeedData(userName: 'User 3', likeCount: 40, content: '오늘 저녁은 맛있었다'),
      FeedData(userName: 'User 4', likeCount: 56, content: '오늘은 미용실을 갔다'),
      FeedData(userName: 'User 5', likeCount: 32, content: '샤라랄라랄~'),
      FeedData(userName: 'User 6', likeCount: 52, content: '내일은 뭐 먹지?'),
      FeedData(userName: 'User 7', likeCount: 12, content: '배고픈데?'),
      FeedData(userName: 'User 8', likeCount: 3, content: '오늘은 다이어트!'),
      FeedData(userName: 'User 9', likeCount: 42, content: '오늘 점심은 맛있었다'),
    
    ];
    
    class FeedList extends StatelessWidget {
      const FeedList({super.key});
    
    
    
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          itemCount:feedDataList.length, itemBuilder: (context, index) => FeedItem(feedData: feedDataList[index]),);
      }
    }
    
    class FeedItem extends StatelessWidget {
      final FeedData feedData;
    
      const FeedItem({required this.feedData, super.key});
    
      @override
      Widget build(BuildContext context) {
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Padding(padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Row(
                    children: [
                      Container(
                        height: 40, width: 40,
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(20),
                          color: Colors.blue.shade300,
                        ),
                      ),
                      const SizedBox(width: 8,),
                      Text(feedData.userName)
                    ],
                  ),
                  const Icon(Icons.more_vert)
                ],
              ),
            ),
            const SizedBox(height: 8,),
            Container(
              width: double.infinity,
              height: 280,
              color: Colors.indigo.shade300,
            ),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Row(
                    children: [
                      IconButton(onPressed: () {}, icon: const Icon(Icons.favorite_outline)),
                      IconButton(onPressed: () {}, icon: const Icon(CupertinoIcons.chat_bubble)),
                      IconButton(onPressed: () {}, icon: const Icon(CupertinoIcons.paperplane)),
                    ],
                  ),
                  IconButton(onPressed: () {}, icon: const Icon(CupertinoIcons.bookmark)),
                ],
              ),
            ),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 24),
              child: Text('좋아요 ${feedData.likeCount}개', style: const TextStyle(fontWeight: FontWeight.bold),),
            ),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 4),
              child: RichText(text: TextSpan(children: [
                TextSpan(text: feedData.userName, style: TextStyle(fontWeight: FontWeight. bold)),
                TextSpan(text: feedData.content)
              ],
                style: TextStyle(color: Colors.black)
              )),
            ),
            const SizedBox(height: 8)
          ],
        );
      }
    }
    728x90

     

     

     

    search_screen.dart

    import 'package:flutter/material.dart';
    
    class SearchScreen extends StatelessWidget {
      const SearchScreen({super.key});
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: SingleChildScrollView(
            child: Column(
              children: [
                SearchTextBar(),
                SearchGrid(),
              ],
            ),
          ),
        );
      }
    }
    
    class SearchTextBar extends StatelessWidget {
      const SearchTextBar({super.key});
    
      @override
      Widget build(BuildContext context) {
        return SizedBox(
          height: 60,
          child: Padding(
            padding: const EdgeInsets.all(8),
            child: TextField(
              cursorColor: Colors.black,
              decoration: InputDecoration(
                  prefixIcon: const Icon(Icons.search),
                  hintText: '검색',
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(20),
                      borderSide: BorderSide(color: Colors.grey.shade200, width: 1)),
                  enabledBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(20),
                      borderSide: BorderSide(color: Colors.grey.shade200, width: 1)),
                  contentPadding: const EdgeInsets.all(0),
                  filled: true,
                  fillColor: Colors.grey.shade200),
            ),
          ),
        );
      }
    }
    
    final gridItems = List.generate(30, (index) => Colors.green.shade300);
    
    class SearchGrid extends StatelessWidget {
      const SearchGrid({super.key});
    
      @override
      Widget build(BuildContext context) {
        return GridView.count(
          padding: EdgeInsets.zero,
          mainAxisSpacing: 4,
          crossAxisSpacing: 4,
          crossAxisCount: 3,
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          children: gridItems.map((color) => Container(color: color)).toList(),
        );
      }
    }

     

     

     

     

    728x90
    반응형

    댓글

Designed by Tistory.