본문 바로가기

Flutter

코딩셰프 - 채팅앱 UI

1. main.dart

import 'package:flutter/material.dart';
import 'package:chat_app/screen/main_screen.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'chat app',
      theme: ThemeData(
        primarySwatch: Colors.blue
      ),
      home: LoginSignupScreen(),
    );
  }
}

 

2. palatee.dart

import 'package:flutter/painting.dart';

class Palatee{

  static const Color iconColor = Color(0xFFB6C7D1);
  static const Color activeColor = Color(0xFF09126C);
  static const Color textColor1 = Color(0XFFA7BCC7);
  static const Color textColor2 = Color(0XFF9BB3C0);
  static const Color facebookColor = Color(0xFF3B5999);
  static const Color googleColor = Color(0xFFDE4B39);
  static const Color backgroundColor = Color(0xFFECF3F9);

}

 

3. main_screen.dart

import 'package:chat_app/config/palatee.dart';
import 'package:flutter/material.dart';

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

  @override
  State<LoginSignupScreen> createState() => _LoginSignupScreenState();
}

class _LoginSignupScreenState extends State<LoginSignupScreen> {
  bool isSignupScreen = true;
  final _formKey = GlobalKey<FormState>();
  String userName = '';
  String userEmail = '';
  String userPassword = '';



  void _tryValidation(){
    final isValid = _formKey.currentState!.validate();
    if(isValid){
      _formKey.currentState!.save();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Palatee.backgroundColor,
      body: GestureDetector(
        onTap: (){
          FocusScope.of(context).unfocus();
        },
        child: Stack(
          children: [
            Positioned(
              top: 0,
              right: 0,
              left: 0,
              child: Container(
                height: 300,
                decoration: BoxDecoration(
                  image: DecorationImage(
                    image: AssetImage('image/red.jpeg'),
                    fit: BoxFit.fill,
                  ),
                ),
                child: Container(
                  padding: EdgeInsets.only(top: 35, left: 20),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      SizedBox(height: 60.0),
                      isSignupScreen?
                      RichText(
                        text: TextSpan(
                            text: 'Welcome',
                            style: TextStyle(
                              letterSpacing: 1.0,
                              fontSize: 15,
                              color: Colors.black45,
                            ),
                            children: [
                              TextSpan(
                                text: ' to My Chatting App',
                                style: TextStyle(
                                  letterSpacing: 1.5,
                                  fontSize: 15,
                                  color: Colors.white,
                                  fontWeight: FontWeight.bold,
                                ),
                              ),
                            ]),
                      ):RichText(
                        text: TextSpan(
                            text: '반갑다 오태식이',
                            style: TextStyle(
                              letterSpacing: 1.0,
                              fontSize: 15,
                              color: Colors.black45,
                            ),
                            children: [
                              TextSpan(
                                text: ' 또왔냐',
                                style: TextStyle(
                                  letterSpacing: 1.5,
                                  fontSize: 15,
                                  color: Colors.white,
                                  fontWeight: FontWeight.bold,
                                ),
                              ),
                            ]),
                      ),
                      SizedBox(height: 10),
                      isSignupScreen?
                      Text('Sign up to contineu',
                          style: TextStyle(
                              color: Colors.white,
                              fontSize: 12,
                              letterSpacing: 1.0)):
                      Text('로그인 빠르게 해줘',
                          style: TextStyle(
                              color: Colors.white,
                              fontSize: 12,
                              letterSpacing: 1.0))
                    ],
                  ),
                ),
              ),
            ),
            //배경
            AnimatedPositioned(
              duration: Duration(milliseconds: 300),
              curve: Curves.easeIn,
              top: 180,
              // right: 20,
              // left: 20,
              child: AnimatedContainer(
                duration: Duration(milliseconds: 300),
                curve: Curves.easeIn,
                padding: EdgeInsets.all(20),
                decoration: BoxDecoration(
                    borderRadius: BorderRadius.all(Radius.circular(20)),
                    color: Colors.white,
                    boxShadow: [
                      BoxShadow(
                        color: Colors.grey.withOpacity(0.3),
                        offset: Offset(0, 2),
                        blurRadius: 10,
                        blurStyle: BlurStyle.normal,
                        spreadRadius: 2,
                      ),
                    ]),
                height: isSignupScreen?300.0:230.0,
                width: MediaQuery.of(context).size.width - 40,
                //각 디바이스의 실제 너비를 구할수 있다.
                margin: EdgeInsets.symmetric(horizontal: 20),
                child: SingleChildScrollView(
                  padding: EdgeInsets.only(bottom: 20),
                  child: Column(
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: [
                          GestureDetector(
                            onTap: () {
                              setState(() {
                                isSignupScreen = false;
                                // _height = 230.0;
                              });
                            },
                            child: Column(
                              children: [
                                Text(
                                  'LOGIN',
                                  style: TextStyle(
                                      fontSize: 16,
                                      fontWeight: FontWeight.bold,
                                      color: !isSignupScreen
                                          ? Palatee.activeColor
                                          : Palatee.textColor1),
                                ),
                                if (!isSignupScreen)
                                  Container(
                                    margin: EdgeInsets.only(top: 3),
                                    height: 2,
                                    width: 55,
                                    color: Colors.orange,
                                  )
                              ],
                            ),
                          ),
                          GestureDetector(
                            onTap: () {
                              setState(() {
                                isSignupScreen = true;
                                // _height = 300.0;
                              });
                            },
                            child: Column(
                              children: [
                                Text(
                                  'SIGNUP',
                                  style: TextStyle(
                                      fontSize: 16,
                                      fontWeight: FontWeight.bold,
                                      color: isSignupScreen
                                          ? Palatee.activeColor
                                          : Palatee.textColor1),
                                ),
                                if (isSignupScreen)
                                  Container(
                                    margin: EdgeInsets.only(top: 3),
                                    height: 2,
                                    width: 55,
                                    color: Colors.orange,
                                  )
                              ],
                            ),
                          ),
                        ],
                      ),
                      if(isSignupScreen)
                      Container(
                        margin: EdgeInsets.only(top: 20.0),
                        child: Form(
                          key: _formKey,
                          child: Column(
                            children: [
                              TextFormField(
                                validator: (value){
                                  if(value!.isEmpty || value.length<4){
                                    return '길이 4글자 이상 입력해라';
                                  }
                                  return null;
                                },
                                key: ValueKey(1),
                                onSaved: (value){
                                  userName = value!;
                                },
                                decoration: InputDecoration(
                                  prefixIcon: Icon(Icons.account_circle,  //내가 해결한 부분, prefix align을 해결했다.
                                      color: Palatee.iconColor),
                                  enabledBorder: OutlineInputBorder(
                                      borderSide: BorderSide(
                                        color: Palatee.textColor1,
                                      ),
                                      borderRadius:
                                          BorderRadius.all(Radius.circular(35.0))),
                                  focusedBorder: OutlineInputBorder(
                                      borderSide: BorderSide(
                                        color: Palatee.textColor1,
                                      ),
                                      borderRadius:
                                          BorderRadius.all(Radius.circular(35.0))),
                                  hintText: 'User name',
                                  hintStyle: TextStyle(
                                    fontSize: 14,
                                    color: Palatee.textColor1
                                  ),
                                  contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                                ),

                              ),
                              SizedBox(height: 15),
                              TextFormField(
                                validator: (value){
                                  if(value!.isEmpty || !value.contains('@')){
                                    return '형식에 맞게 이메일 주소를 입력해주오';
                                  }
                                  return null;
                                },
                                onSaved: (value){
                                  userEmail = value!;
                                },
                                key: ValueKey(2),
                                decoration: InputDecoration(
                                  prefixIcon: Icon(Icons.email,  //내가 해결한 부분, prefix align을 해결했다.
                                      color: Palatee.iconColor),
                                  enabledBorder: OutlineInputBorder(
                                      borderSide: BorderSide(
                                        color: Palatee.textColor1,
                                      ),
                                      borderRadius:
                                      BorderRadius.all(Radius.circular(35.0))),
                                  focusedBorder: OutlineInputBorder(
                                      borderSide: BorderSide(
                                        color: Palatee.textColor1,
                                      ),
                                      borderRadius:
                                      BorderRadius.all(Radius.circular(35.0))),
                                  hintText: 'e-mail',
                                  hintStyle: TextStyle(
                                      fontSize: 14,
                                      color: Palatee.textColor1
                                  ),
                                  contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                                ),
                              ),
                              SizedBox(height: 15),
                              TextFormField(
                                validator: (value){
                                  if(value!.isEmpty || value.length<6){
                                    return '비밀번호는 6글자 이상 입력할것!!';
                                  }
                                  return null;
                                },
                                onSaved: (value){
                                  userPassword = value!;
                                },
                                key: ValueKey(3),
                                decoration: InputDecoration(
                                  prefixIcon: Icon(Icons.lock,  //내가 해결한 부분, prefix align을 해결했다.
                                      color: Palatee.iconColor),
                                  enabledBorder: OutlineInputBorder(
                                      borderSide: BorderSide(
                                        color: Palatee.textColor1,
                                      ),
                                      borderRadius:
                                      BorderRadius.all(Radius.circular(35.0))),
                                  focusedBorder: OutlineInputBorder(
                                      borderSide: BorderSide(
                                        color: Palatee.textColor1,
                                      ),
                                      borderRadius:
                                      BorderRadius.all(Radius.circular(35.0))),
                                  hintText: 'password',
                                  hintStyle: TextStyle(
                                      fontSize: 14,
                                      color: Palatee.textColor1
                                  ),
                                  contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                                ),

                              )
                            ],
                          ),
                        ),
                      ),
                      if(!isSignupScreen)
                        Container(
                          margin: EdgeInsets.only(top: 20.0),
                          child: Form(
                            key: _formKey,
                            child: Column(
                              children: [
                                TextFormField(
                                  validator: (value){
                                    if(value!.isEmpty || !value.contains('@')){
                                      return '형식에 맞게 이메일 주소를 입력해주오';
                                    }
                                    return null;
                                  },
                                  onSaved: (value){
                                    userEmail = value!;
                                  },
                                  key: ValueKey(4),
                                  decoration: InputDecoration(
                                    prefixIcon: Icon(Icons.email,  //내가 해결한 부분, prefix align을 해결했다.
                                        color: Palatee.iconColor),
                                    enabledBorder: OutlineInputBorder(
                                        borderSide: BorderSide(
                                          color: Palatee.textColor1,
                                        ),
                                        borderRadius:
                                        BorderRadius.all(Radius.circular(35.0))),
                                    focusedBorder: OutlineInputBorder(
                                        borderSide: BorderSide(
                                          color: Palatee.textColor1,
                                        ),
                                        borderRadius:
                                        BorderRadius.all(Radius.circular(35.0))),
                                    hintText: 'e-mail',
                                    hintStyle: TextStyle(
                                        fontSize: 14,
                                        color: Palatee.textColor1
                                    ),
                                    contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                                  ),

                                ),
                                SizedBox(height: 15),
                                TextFormField(
                                  validator: (value){
                                    if(value!.isEmpty || value.length<6){
                                      return '비밀번호는 6글자 이상 입력할것!!';
                                    }
                                    return null;
                                  },
                                  onSaved: (value){
                                    userPassword = value!;
                                  },
                                  key: ValueKey(5),
                                  decoration: InputDecoration(
                                    prefixIcon: Icon(Icons.lock,  //내가 해결한 부분, prefix align을 해결했다.
                                        color: Palatee.iconColor),
                                    enabledBorder: OutlineInputBorder(
                                        borderSide: BorderSide(
                                          color: Palatee.textColor1,
                                        ),
                                        borderRadius:
                                        BorderRadius.all(Radius.circular(35.0))),
                                    focusedBorder: OutlineInputBorder(
                                        borderSide: BorderSide(
                                          color: Palatee.textColor1,
                                        ),
                                        borderRadius:
                                        BorderRadius.all(Radius.circular(35.0))),
                                    hintText: 'password',
                                    hintStyle: TextStyle(
                                        fontSize: 14,
                                        color: Palatee.textColor1
                                    ),
                                    contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                    ],
                  ),
                ),
              ),
            ),
            //텍스트폼 필드
            AnimatedPositioned(
              duration: Duration(milliseconds: 300),
              curve: Curves.easeIn,
              top: isSignupScreen?450:380,
                right: 0,
                left: 0,
                child: Center(
                  child: Container(
                    padding: EdgeInsets.all(15),
                    height: 90,
                    width: 90,
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(50),
                    ),

                    child: GestureDetector(
                      onTap: (){
                        _tryValidation();
                      },
                      child: Container(
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(50),
                            gradient: LinearGradient(
                            colors: [
                              Colors.orange,
                              Colors.red,
                            ],
                              begin: Alignment.topRight,
                              end: Alignment.bottomLeft
                          ),
                          boxShadow: [
                            BoxShadow(
                              color: Colors.black.withOpacity(0.3),
                              spreadRadius: 1,
                              blurRadius: 1,
                              offset: Offset(0, 1),
                            ),
                          ]
                        ),
                        child: Icon(Icons.arrow_forward,
                        color: Colors.white),

                      ),
                    ),
                  ),
                )),
            //버튼
            AnimatedPositioned(
              duration: Duration(milliseconds: 300),
              curve: Curves.easeIn,
              top: isSignupScreen? MediaQuery.of(context).size.height-125:MediaQuery.of(context).size.height-165,
                right: 0,
                left: 0,
                child: Column(
                  children: [
                    Text(isSignupScreen?'or Signup with':'회원이면 빠르게 로그인하자'),
                    SizedBox(height: 10),
                    TextButton.icon(
                        onPressed: (){},
                        style: TextButton.styleFrom(
                          primary: Colors.white,
                          minimumSize: Size(155, 40),
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(20)
                          ),
                          backgroundColor: Palatee.googleColor,
                        ),

                        icon: Icon(Icons.add),
                        label: Text('Google'))
                  ],

                )),
            //아래 구글 로그인
          ],
        ),
      ),
    );
  }
}