728x90
728x90

 

 

Concurrently 를 이용해서 프론트, 백 서버를 한번에 켜보자.

 

$npm install concurrently --save

먼저 라이브러리를 설치한다.

 

 

 

 

 

 

 

Line 10 추가

 

이제 boiler-plate 디렉토리에서

$npm run dev

로 한번에 프론트, 백 서버를 켤 수 있다.

728x90
728x90

 

해결 방법

1) 개발자 도구 이용 
- 개발자들만 사용 ->제한적

2) JsonP 방식 
- 프론트엔드 부분만 고칠 수 있는 상황일 때
- 모든 request 를 get request로 바꿔서 보냄 

3)
- 백엔드, 프론트엔드 모두 다 제어가능 할 때

4) Proxy 사용

 

 

Proxy 

Proxy란?

 

 

 

Proxy로 CORS 에러를 해결해보자.

 

참고 사이트

create-react-app.dev/docs/proxying-api-requests-in-development/

 

Proxying API Requests in Development | Create React App

Note: this feature is available with react-scripts@0.2.3 and higher.

create-react-app.dev

 

 

 

http-proxy-middleware 를 설치한다. 

$ npm install http-proxy-middleware --save

 

 

그 후 src/setupProxy.js를 만들고 아래 코드를 추가한다.

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:5000',
      changeOrigin: true,
    })
  );
};

 

다시 백엔드를 켜고 프론트 엔드 서버를 켜서 확인해보자.

 

CORS 에러는 없어졌으나 오류가 여전하다...

 

 

해결 방법

: http-proxy-middleware를 다른 디렉토리에 설치해서 에러가 발생한거였다. 'boiler-plate/client'에 설치하면 에러가 해결된다!

 

728x90
728x90

 

그동안은 Client가 없어서 Postman으로 보냈으나, 이제는 Client쪽도 구현이 됐기 때문에 AXIOS를 통해서 Request를 보내보자.

axios 라이브러리를 다운받자.

$npm install axios --save

 

 

 

 

 

간단하게 테스트해보자. LandingPage.js를 아래와 같이 수정하고 여기서 보낸 getRequest를 받기 위해 server쪽인 index.js에도 두번째 코드를 추가해주자.

 

 import React, {useEffect} from 'react'
import axios from 'axios';

 function LandingPage(){//Functional Component 만들기
     
    
    useEffect(() => {
        axios.get('api/hello')      //endpoint. getRequest를 server 즉 index.js로 보내질 것
        .then(response => console.log(response.data))   //server 에서 돌아온 response를 콘솔창에 출력해봄
    }, [])
    
    
    return(
         <div>
          LandingPage
         </div>
     )
 }

 export default LandingPage

 

 

 

app.get('api/hello', (req,res) => {
    res.send("안녕하세요~")
})

 

 

이제 서버를 켜보자. 이때 client 디렉토리가 아닌 그 상위 디렉토리인 boler-plate 디렉토리에서 아래의 명령어를 실행시켜야한다.  또한 이전에 디렉토리 구조를 변경했기 때문에 package.json 파일에서

"backend""nodemon server/index.js" 로 수정해줘야 백엔드가 실행된다. 

$npm run backend

 

 

이제 프론트 서버도 켜보자. client 디렉토리로 이동 후 

$npm run start

 를 실행하자. 

 

 

결과

 

request가 잘 갔다 왔는지 확인을 위해 콘솔창을 켜보자. (fn + F12)

 

에러가 발생했다.

 

이유 : 사용자의 서버 포트는 5000번이고 클라이언트 포트는 3000번이기 때문
=> 클라이언트가 3000번으로 요청을 보냈으나 서버는 받지 못함 

 

그럼 5000번으로 요청을 보내보자.

useEffect(() => {
        axios.get('http://localhost;5000/api/hello')      //endpoint. getRequest를 server 즉 index.js로 보내질 것
        .then(response => console.log(response.data))   //server 에서 돌아온 response를 콘솔창에 출력해봄
    }, [])

 

 

CROS 에러

 

여전히 에러가 있다.

 

그 이유는 CORS 정책 때문이다. 만약 외부의 다른 클라이언트에서 요청을 보내면 보안상의 이슈가 있을 수 있기 때문에 CORS 정책이 있는것!
(CORS란? : Cross-Origin Resource Sharing의 약자로 서로 다른 Origin 사이에서 자원을 공유할 때 사용되는 정책)

 

 

 

다음 포스팅에서는 CORS 에러 해결방법에 대해 알아보자.

728x90
728x90

문제 링크 : swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV7I5fgqEogDFAXB

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

 

 

 

 

 

접근 방법

재귀를 이용한 DFS로 풀었다. set 자료구조로 삽입시 중복이 되지 않게 했다.

테스트 케이스가 반복되므로 매 테스트케이스가 끝날때마다 초기화를 잘 해줘야 에러가 안 뜬다. 주의하자!

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

int map[4][4]={0};

//위,오,아,왼
int dr[4]={-1,0,1,0};
int dc[4]={0,1,0,-1};

vector<int> nVec;
set<int> ansVec;

void DFS(int r, int c, int toPick){
    
   
    if(toPick==0){
        int num = nVec[0]*1000000+nVec[1]*100000+nVec[2]*10000+nVec[3]*1000+nVec[4]*100+nVec[5]*10+nVec[6];
        
        ansVec.insert(num);
        return;
    }
    
    
    for(int i=0; i<4; i++){
        
        int nr=r+dr[i];
        int nc=c+dc[i];
        
        if(nr>=4 || nr<0 || nc>=4 || nc<0) continue;
        
        nVec.push_back(map[nr][nc]);    //next 지점이 범위 안에 들어오면 push
        DFS(nr,nc,toPick-1);
        nVec.pop_back();				//원상복구
    }
}

int main(){

    int T;
    cin >> T;
    
    int ans=0;
    for(int test_case = 1; test_case <= T; test_case++){
        
         for(int i=0; i<4; i++){
           for(int j=0; j<4; j++){
               cin>>map[i][j];
           }
         }
        
        for(int i=0; i<4; i++){
            for(int j=0; j<4; j++){
                nVec.push_back(map[i][j]);          //첫 시작지점 넣음
                DFS(i,j,6);
                nVec.clear();					 //초기화 필수

            }
        }
        
        cout << "#" << test_case << " " << ansVec.size() << "\n";
        
        //초기화 필수
        ans=0;
        ansVec.clear();
        nVec.clear();
        
    }
    
    return 0;
}

 

 

 

 

처음에는 set이 아닌 vector를 이용해서 find()를 통해 중복검사를 했는데 제한시간 2초를 넘겨서 시간초과가 떴다. 그래서 set으로 바꿔봤는데 바로 통과됐다.

if(toPick==0){
        int num = nVec[0]*1000000+nVec[1]*100000+nVec[2]*10000+nVec[3]*1000+nVec[4]*100+nVec[5]*10+nVec[6];
       
        if(find(ansVec.begin(),ansVec.end(),num) == ansVec.end()){
            ansVec.push_back(num);
        }
        return;
}

 

 

728x90
728x90

Create-React-App의 구조를 우리가 만드려는 목적에 맞게 고쳐보자.

 

먼저 Create-React-App의 구조를 봐보자.

참조 : create-react-app.dev/docs/folder-structure/

 

Folder Structure | Create React App

After creation, your project should look like this:

create-react-app.dev

 

 

 

 

 

 

 

 

HOC이란? 

Higher-Order Component의 약자로, 컴포넌트를 포함한 메소드이다.

 

 

 

위와 같이 폴더 및 파일을 생성하고 각 js 파일에 Functional Component를 만든다.

 

 

 

 

 

이제 App.js 파일을 수정해보자. App.js 에서는 각 페이지간에 이동할 때 라우팅 해주는 역할을 한다. 이렇게 페이지 이동을 할 때 React Router Dom 이라는 것을 사용한다.  

참조 : reactrouter.com/web/example/basic

 

React Router: Declarative Routing for React

Learn once, Route Anywhere

reactrouter.com

 

 

먼저 client 디렉토리로 이동 후 React Router Dom을 다운받자.

$npm install react-router-dom --save

 

 

 

 

import React from 'react'

import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom"; 



import LandingPage from './components/views/LandingPage/LandingPage';
import LoginPage from './components/views/LoginPage/LoginPage';
import RegisterPage from './components/views/RegisterPage/RegisterPage';

function App() {
  return (
    <Router>
      <div>
         
        {/*
          A <Switch> looks through all its children <Route>
          elements and renders the first one whose path
          matches the current URL. Use a <Switch> any time
          you have multiple routes, but you want only one
          of them to render at a time
        */}
        <Switch>
          <Route exact path="/" component={LandingPage} />
          <Route exact path="/login" component={LoginPage} />
          <Route exact path="/register" component={RegisterPage} />
        </Switch>
      </div>
    </Router> 
  );
} 

export default App;


App.js 를 위와 같이 작성한다.

 

 

 

 

npm run start 결과

 

 

 

 

 

 

 

 

728x90
728x90

출처 : 인프런_따라하며 배우는 노드, 리액트 시리즈 — 기본 강의

 

이전까지는 Nodejs로 Server 쪽을 구성해봤다면,

이제 여기서부터는 리액트로 Client 쪽을 구성해보자. 

(Client 를 만들면 더이상 postman으로 send하지 않아도 된다!)

 

1. 리액트란?


- 2013년에 페이스북이 만든 라이브러리

- 컴포넌트들로 이루어져 있어 재사용성 뛰어남

- Virtual DOM을 사용하여 diffing(스냅샷과 바교하여 업데이트된 부분 찾는것)

 

 

2. Create React App 으로 리액트 시작하기

- 원래 리액트 앱 실행을 하기 위해선 webpack(번들화), babel(최신 자바스크립트 문법 지원) 설정을 위한 시간이 많이 소요됨.

- 이러한 불편함을 해소시켜주는게 create-react-app Command

(* webpack 은 client/src 디렉토리만 관리해준다. -> 이미지 파일들은 public 디렉토리가 아닌 src 디렉토리에 넣는것이 좋다. )

 

2-1) create-react-app 다운

$npx create-react-app . 

 

 

명령어를 실행하니 위와 같은 에러가 발생했다. 

 

 

 

c compiler를 설치해서 문제를 해결하자.

$xcode-select --install

그러나 아래와 같은 또 에러가 발생했다.

xcode-select: error: command line tools are already installed, use "Software Update" to install updates

 

 

시키는대로 해보자.

softwareupdate --install -a

그러나 아래와 같이 업데이트 할 수 있는게 없다는 메세지가 출력됐다.

No updates are available.

 

 

 

다 지우고 다시 설치해서 문제를 해결할 수 있었다.

$sudo rm -rf $(xcode-select -print-path)
$sudo xcode-select --install    

설치 중

 

 

삭제후 다시 설치하니 정상작동 된다.

 

 

 

- 원래 create-react-app할 때 

$npm install -g create-react-app

 

으로 global(내 맥북) 디렉토리에 다운을 받아서 사용했다. 그러나 npx를 이용해서 다운받지 않고 사용이 가능하다.

 

 

 

 

 

 

 

 

 

 

 

3. NPX 장점

- NPM 레지스트리에서 create-react-app을 찾아서(Look up)  이용할 수 있다.

(원래는 npm install -g create-react-app을 통해 global 디렉토리에 다운 받았었음)

 - 디스크 공간 낭비 x(컴퓨터에 다운받지 않으므로)

 - 항상 최신 버전 사용 가능

 

 

 

3-1) 참고 1

NPM(Node Package Manager)의 역할

- 레지스트리 같은 저장소 역할 -> 라이브러리(bcrypt, body-parser...등)를 저장한다.

- 빌드할 때 사용한다.

 

3-2) 참고2

[NPM install Locally]

'-g' 를 붙이지 않으면 디폴트로 로컬에 저장된다. 즉 아래 사진과 같이 node_modules 디렉토리에 저장된다.

[NPM install Globally]

'-g' 플래그를 주면 프로젝트 내에서 다운받는게 아니라, 컴퓨터에 다운이 받아진다.

 

 

 

 

 

4. react app 실행하여 화면 렌더링 하기

실행시켜보자. 생성한 client 디렉토리로 이동하여 npm run start 를 터미널에 입력하니 아래와 같은 브라우저 창이 열렸다.

 

이것은 client/src/App.js 가 렌더링돼서 나온 것이다.

 

 

 

 

 

client/src/index.js에서 line9에 원하는 컴포넌트를 넣으면 되는것이다.

 

 

 

line9를 바꿔보면 아래와 같이 바뀐다.

 

line 11의 'root'라고 아이디를 지정해줌으로써 client/public/index.html의 id="root"인 곳에 보여지게 한다.

 

 

 

 

 

 

 

728x90
728x90

참고 : 유투브 — 센치한 개발자

<기본 설정 및 기초 이해하기>

[1. 라이브러리 다운]

[2. RecyclerView 컴포넌트 붙이기]

  • activity_news.xml 파일에 layout을 추가한다.
  • 이곳에 뉴스 앱 화면을 보여줄 것이다.

[3. 액티비티 클래스에 내용 구현하기]

  • NewsActivity.java : activity_news.xml 와 매칭 될 액티비티를 새로 만든다.

[4. 리스트에 사용할 어댑터(리스트의 항목들 제어) 붙이기]

  • MyAdapter.java 를 새로 작성한다. 어댑터를 구현하는 클래스이며 어떠한 리스트들을 보여줄지 상세한 내용을 담는다.

  • 빨간줄이 뜨는 것에 대해 alt+Enter 로 class 를 import 해준다.
  • line 37 의 빨간줄이 없어지지 않는 이유 : RecyclerView를 보여주는 액티비티 xml과 각 줄별로 내용을 보여주는 레이아웃 xml 이 필요한데, 아직 후자의 xml 파일이 없기 때문이다.

[5. row_news.xml 작성]

  • 그림 2와 같이 만들어보자.

  • 그림 2에 들어갈 레이아웃을 위해 row_news.xml 파일을 새로 만들어 코드를 작성한다.
  • ImageView와 TextView 를 이용한다.
  • line 27 : 색상값 총 8자리 중 맨 앞자리 2자리는 투명도(16진수) 값이다.
  • line 43 : ellipsize는 텍스트 내용이 많아서 정해진 칸을 넘어갈 때 “…” 을 사용함으로써 내용이 더 있다는 것을 나타내고자 할때 쓴다.

  • line 37 : 레이아웃을 연결해준다. 위와 같이 row_news 로 수정하면 오류가 사라진다.
  • line33~40 : row 한 줄에 해당하는 파일(row_news.xml) 을 연결시켰다.
  • line 17~24 : 그 한 row 에 들어가는 요소(Text,Image..) 를 정의하는 것이다.
  • MyViewHolder 클래스에서 findViewById() (하위 컴포넌트를 연결하기 위해 찾아가는 함수) 를 통해 하위 컴포넌트를 연결한다.

정리 : row_news.xml 이라는 전체 파일은 line 33–40의 onCreateViewHolder() 에서, 한개의 row 안에 들어가는 텍스트와 이미지는 line 20의 MyViewHolder() 에서 정의한다.

  • line 45 : row_news.xml 의 최상위 뷰가 LinearLayout 이므로 수정
  • line 46 — inflate : 특정한 컴포넌트(여기서는 리사이클러 뷰)의 특정 항목의 레이아웃을 바꾼다. (여기서는 액티비티에서 갖고 오는 뷰가 아님)

  • 한 row 안의 요소들을 다루기 위해 변수 선언.
  • findViewById 앞에 v. 을 붙인 이유는? => 부모 xml 뷰가 누군지 알 수 없으므로 명확하게 row_news.xml이 부모라고 지정한 것이다.
  • line 26 : 뷰홀더 클래스가 받는 값을 TextView 에서 View 로 수정해준다.

참고 : 나중에 발견한 사실인데, 파일 명에 저렇게 빨간줄이 많이 뜨는 이유는 위 화면의 line 12 때문이다. line 12를 지우면 오류가 해결된다.

참고 : 뷰홀더 클래스는 메모리 관리와 성능 향상을 위해 안드로이드가 제공하는 클래스이다. (재활용 가능)

  • line 25,26 : 리사이클러 뷰를 액티비티에서 불러서 activity_news 라는 액티비티를 만들었다. 거기에 리사이클러뷰를 연결했다.
  • line 30 : 하나의 row 사이즈를 맞췄다.
  • line 33,34 : manager을 달아줌.
  • line 37 오류 해결 방법 : 아래와 같이 line 21에 코드 한 줄을 추가 해준다.

  • line 39,40 : 아래 화면의 생성자로 값을 넘겨주는 역할을 한다. NewsActivity.java 를 계속 참조하면 메모리를 낭비할 수도 있고 화면이 사라질 수도 있기 때문에 아예 값을 넘겨 받아 이런 위험을 방지한다.

MyAdapter.java 파일 안의 생성자

  • MyViewHolder 클래스는 mDataset의 크기(mDataset.length)만큼 반복을 하는데, 매 반복마다 mDataset에서 값을 꺼내어 매칭을 시켜준다. (by v.findViewById())
  • 반복한 홀더를 바인딩 즉, 데이터를 셋팅하는 곳이 위 화면의 line 54 이다.
  • row_news.xml 에 표시되는 내용들은 어디서 가져와야 하는 것일까? => Adapter 를 처음 설정 할 때 mDataset 변수에 값을 넣어줘야 여기서 가져올 수 있다. (mDataset 변수 : 각 row 마다 보여줄 값을 들고 있는 원본 데이터 변수)

  • 그 값들을 여기에 넣어주면 화면상으로는 row_news.xml 에 나타나게 된다.

[중간 점검]

  • line 12를 MainActivity 에서 NewsActivity로 바꾼 후 실행해보자.
  • Sample1 이 튕겨서 종료되는 오류가 발생한다.

  • activity_news.xml 파일의 line 8을 위와 같이 수정한 후 빌드해보자.

  • mDataset을 {“1”, “2”} 로 두 개를 넘겨줬는데 1만 뜨는 오류가 발생했다.

  • row_news.xml 파일의 line 4를 match_parent 에서 wrap_content 로 변경해주면 정상적으로 실행됨을 확인할 수 있다.
728x90
728x90

참고 : 유투브 — 센치한 개발자

[목표 : 위의 로그인 화면을 디자인 해보자.]

[1. 레이아웃을 그릴 xml 파일 생성]

  • 왼쪽의 res 폴더 안의 layout 폴더에 ‘activity-login.xml’ 파일을 만든다.

  • ‘MainActivity.java’ 파일과 위에서 새로 만든 ‘activity_login.xml’ 파일 매칭을 위해 line 12 를 위와 같이 수정해준다.

[2. TextView로 LOGIN 글자 삽입]

[3. ImageView로 이미지 삽입]

  • 프로젝트를 만들면 들어있는 기본 앱 아이콘 이미지를 쓴다.
  • background로 넣거나 src로 넣는 방법이 있다.
  • background로 넣으면 이미지가 깨지므로 src를 이용한다.

  • 이미지가 삽입된 것을 확인할 수 있다.
  • width 는 “match_parent”로 height는 “wrap_content”로 설정한다.
  • 그런데 여기서 이미지가 가로 사이즈에 맞춰서 늘어나지 않은 것을 확인할 수 있는데, 이는 src 방법으로 이미지를 삽입했기 때문이다.

  • background를 이용하여 이미지를 삽입하면 위와 같이 이미지가 깨져서 삽입된다.
  • background는 이미지를 너비와 높이에 무조건 꽉 채운다. 그러나 width 설정을 “wrap_content” 로 한 후 중앙으로 보내는 설정을 해 주면 된다. (복잡하니 그냥 src를 이용하여 이미지를 삽입하도록 한다.)

[4. EditText로 이메일과 패스워드 입력 창 생성]

[5. Button 생성]

[6. 가로로 TextView 두 개 삽입]

  • weightSum을 이용하여 절반씩 text를 배치한다.

[7. Text Color , Size 바꾸기]

  • line 13, 84 : 글씨 색을 바꾼다.
  • line 14,73,84 : 글씨 크기를 바꾼다.

[8. Button Color를 바꾸기 위해 색깔 따오기]

nanyoungkim.tistory.com/13

 

Pixlr Editor로 색상코드(HEX) 알아내기

안드로이드 스튜디오에서 로그인 화면을 만드는 도중에, 버튼 색을 지정하기 위해 주어진 버튼 색의 핵사값을 알아내야 했다. Pixlr Editor 로 임의의 색깔의 핵사값을 알아내보자. Step 1)부터 하면

nanyoungkim.tistory.com

위의 링크에서 먼저 버튼 색의 HEX 값을 알아오자.

 

 

 

 

 

  • 안드로이드에서 제공하는 머터리얼 디자인을 사용하기 위해 ‘Gradle Scripts — build.gradle’ 에 line 30을 추가한다. 그 후 오른쪽 상단의 Sync Now 를 클릭하여 관련 소스들을 다운로드한다.
  • 주의 : 버전이 바뀌면서 에러가 발생한다. 해결을 위해 유투브 강의 댓글을 서치한 결과 문제를 해결할 수 있었다.

 

  • line 30과 같이 implementation ‘com.google.android.material:material:1.0.0-rc01’ 라고 타이핑한다.
  • 그 후 Sync Now 를 클릭하면 싱크가 잘 맞는것을 확인할 수 있다.

 

 

 

[9. 상업용 이미지 파일 다운]

  • present 를 검색한 후, PRICE는 ‘Free’로, LICENSE TYPE은 ‘For commercial use’로 선택한다.

  • 원하는 사진을 다운로드 한다.
  • Size는 128px, 64px, 48px 세 종류를 다운한다.
  • 참고 : 더 심플한 이미지를 원하면 https://material.io/resources/icons/?style=baseline 에서 다운로드가 가능하다. (google에 ‘material icon’ 검색)

 

[10. 다운로드 한 이미지 파일 프로젝트에 넣기]

  • 왼쪽 상단의 Android를 Project로 바꾼다.

  • app — src — main — res — drawable 폴더안에 다운로드 한 이미지 파일을 ctrl +v 하여 복사한다.
  • 이때, 이미지 파일은 소문자와 언더바를 이용하여 간단하게 작성하도록 한다.

  • line 21을 수정했더니 안드로이드 기본 아이콘에서 icon_present.png 파일로 바뀐 것을 확인할 수 있다.
  • line 19를 수정하여 아이콘 크기를 조금 줄여보았다.
  • 참고 : 원래는 원하는 화면 사이즈에 맞는 폴더 명을 지정한 후 이미지를 적절하게 넣어주어야 한다.

  • 사이즈를 보는 방법: Pixel(Device for Preview) 클릭 — Add Device Definition 클릭 — 오른쪽 연필 모양의 Edit this AVD 클릭 — ‘5.96 1440x2560 560dpi’ 확인 가능.

그러나 여기 기초 강의에서는 그냥 drawable 폴더에 이미지를 넣는다.

[11. Hint 이용하여 텍스트 넣기]

  • line 29, 35를 추가한다.

[11. 버튼 라운딩 처리 하기]

  • 우리가 원하는 버튼 디자인은 타원형이나, 기존의 Button 은 네 모서리를 둥글게 하는 기능이 없다. 이를 해결해보자.

  • drawable폴더에 xml 파일을 한개 더 생성한다.

  • selector 라는 디자인 요소를 정의한다.
  • item : 정상 상태일 때를 정의한다.
  • shape : 정상 상때일 때의 모양을 정의한다.
  • solid : 색을 정의한다.
  • corners : 모서리를 둥글게 한다.

  • line 44,61 : 모서리를 둥글게 처리하였다.
  • line 45,62 : 텍스트 컬러를 변경하였다.

[12. 버튼 컬러 변경하기]

  • bin_blue.xml 파일에 8번에서 딴 색깔 여섯자리를 line 6에 적용한다.bin_darkblue.xml 파일도 하나 생성하여 위와 같은 방법으로 색깔 6자리를 타이핑한다.

  • activity_login.xml 파일의 line 44, 61 : 버튼 컬러가 바뀜을 확인할 수 있다.

[13. 중간 점검]

  • 빌드를 하고 Email 칸에 타이핑을 하였으나 ‘Email’이라는 글자가 사라지는 것을 확인하였다. 이를 해결해보자.

[14. TextInputLayout & TextInputEditText 사용하기]

  • 위와 같이 타이핑하고 빌드해보자.

  • 타이핑을 하면 Email 이라는 글자가 사라지는 것 대신 위로 올라감을 확인할 수 있다.

[15. 여백 주기]

  • line 14, 24,32,46,64,73 과 같이 layout_marginBottom 을 16dp로 지정해준다.

결과

  • line 6, 7 : 양 옆에 padding 을 준다.
  • line 8 : 위에 padding 을 준다.

[16. 버튼에 이미지 넣기]

  • 버튼에 아이콘을 추가하기 위해 line 68을 추가했더니 오른쪽과 같은 결과가 나왔다. 크기 문제를 해결해보자. (해결책 — RelativeLayout 사용)

[17. 버튼이 눌렸을 때 효과 주기]

  • 좌측 프로젝트에서 app-src-main-res-values-colors.xml 파일에 색을 정의한다.

  • bin_blue.xml 파일을 위와 같이 수정한다.
  • 3개의 아이템 엘리멘트 : 각각 버튼이 눌린 상태(Yellow), 평소 상태(Blue), 누를 수 없는 상태(Gray)를 위한다.
  • colors.xml 파일에 색을 정의했으므로 “@color/colorYellow” 와 같이 쓸 수 있는 것이다.

  • bin_darkblue.xml 파일도 위와 같은 방식으로 수정해준다.

[17. 정렬 다듬기]

  • Log in 버튼과 Log in with Facebook 버튼을 만들기 위해 LinearLayout 안에 ImageView와 TextView를 사용한다.
  • 전체적인 틀은 LinearLayout 을 이용하고 weightSum 으로 그림과 텍스트 간의 비율을 맞춰준다.
  • 그러나 실행화면을 보면 ‘Log in’ 글자와 ‘Log in with Facebook’ 글자가 살짝 오른쪽으로 치우친 것을 확인할 수 있다. 이를 해결해보자.

[18. 입력한 값 가져오기]

  • 참고 : RelativeLayout은 버튼이 아니므로 clickable = “true” 가 필요하다.

  • line 40,55,63 : MainActivity.java 에게 xml 파일 안의 컴포넌트들의 존재를 알려주기 위해 id 를 지정한다.

  • line 12,13 : 컴포넌트 종류를 앞에 써 주고 그 뒤에 변수명을 타이핑하여 변수를 선언한다. (에러가 뜨면 맥 기준에서 alt+Enter 를 통해 class 를 import 해준다. )
  • line23,24,25 : 선언한 변수들에 실제 값들을 대입한다.

  • setClickable — 클릭 가능 여부 설정 / setOnClickListener : 클릭 리스너 설정
  • line 36 : 클릭이 가능하다는 것을 설정해준다.
  • line 37 : 클릭 리스너를 설정한다.
  • line 40,41 : 사용자가 이메일과 패스워드를 입력한 후 로그인을 클릭했을 때 값을 받아온다는 의미이다.

  • Intent 방식 : 값을 주고 받는 하나의 규약.
  • putExtra : key와 value 를 이용하여 값을 찾아온다. (key로 찾아서 value를 빼오는 것)
  • line 48 : 넣은 값을 다음 액티비티로 던지기 시작하겠다는 의미이다.
  • line 45 : 어디로 던질지 정해준다.

  • 값을 잘 받아 왔는지 확인해보자.
  • LoginResultActivity.java 에서 위와 같이 입력한다.
  • line 30 : intent.getDataString() 으로 하지 않은 이유는 MainActivity.java 에서 값을 던질 때 putExtra()로 보냈기 때문이다.

  • 빌드를 한 후, 이메일과 패스워드를 입력하고 로그인 버튼을 누르면 위와 같이 오류가 뜬다. 이를 해결해보자.

  • app — src — res — AndroidManifest.xml에 Activity를 정의해줘야한다.
  • line19–20 과 같이 정의해준다.

  • 그럼 성공적으로 로그인 정보를 스크린에 띄울 수 있다.

[19. 입력한 값이 올바른지 체크하기]

  • MainActivity.java 에 addTextChangedListener을 이용한 코드를 작성한다.
  • 이메일은 123@gmail.com 이고 패스워드는 1234일 때만 로그인 버튼을 클릭할 수 있도록 하는 것이 목표이다.
  • 어떤 값이 들어가는지 알기 위해 Log를 찍어보자.(Logcat 확인)
  • line 48의 s 가 입력한 이메일 값이라는 것을 알 수 있었다.
  • 전역변수의 데이터 타입을 CharSequence로 하던가, s를 String형으로 바꿔줘야 한다.

  • 주의 : toString()을 보면 string 을 return 한다고 했는데 null 이면 에러가 발생할 수 있으니 null 값을 체크한 후 toString 을 해야한다.

  • if 괄호 안의 식이 살짝 지저분하다.

  • validation() 함수를 이용하여 간단하게 만들어 보았다.
  • validation() 의 리턴 값에 따라 클릭이 가능하게 혹은 가능하지 않게 설정할 수 있다.
  • 실행하면 오류가 발생한다.
  • 첫번째 오류 : 아무것도 타이핑하지 않고 Log in 버튼을 눌러도 클릭이 된다. (해결 방법 => activity_login.xml파일에서 Log in 버튼이 있는 LinearLayout 의 clickable 을 설정한 코드를 지워준다.)
  • 두번째 오류 : 올바르게 입력하고 Log in 버튼을 눌렀을 땐 클릭이 되지 않는다.

  • validation() 함수를 위와 같이 수정해주면 된다. => 두번째 오류 해결
  • 자바에서는 문자열 비교는 equals()로 해야하기 때문이다.
728x90

+ Recent posts