본문 바로가기

수업 정리

70일차 수업정리(Android Layout)

**대다수의 GUI Programming의 방식

    => 디자인을 위한 파일, 디자인을 동적으로 제어하는 파일을 pair로 제공하는 경우가 많음

        - 디자인 하는 파일에 직접 코드를 작성할 수 있는 방법과 컴포넌트를 드래그 앤 드랍 배치후 조정하는 방식 제공

 

**LinearLayout

    => View를 수직, 수평 방향으로 배치하는 레이아웃

 

**RelativeLayout

    => 위젯과 부모와의 위치 또는 위젯끼리의 관계를 이용하여 배치하는 레이아웃

        - 첫번째 위젯은 부모와의 관계로 배치하고 두번째 위젯 부터는 다른 위젯과의 관계를 이용하여 배치

        - 자바코드에서 사용하지 않는 위젯이라도 다른 위젯과의 관계를 위해서 ID를 설정

    => 레이아웃도 위에서 아래로 읽기 때문에 기준이 되는 위젯을 먼저 생성

<RelativeLayout>
    <View android:id="@+id/a"/>
    <View android:layout_above="@+id/a"/> //이 View는 a의 위에 생성
</RelativeLayout>

 

    => layout_로 시작하는 속성으로 배치

        - left 대신에 start를 사용할 수 있음 : toLeftOf대신에 toStartOf가 가능

        - right 대신에 end를 사용할 수 있음

    => to 대신에 align으로 시작하면 맞춤을 설정

    => alignParent로 시작하면 부모 뷰를 기준으로 맞춤 설정

1. layout 파일 수정

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!--부모뷰의 오른쪽 끝에 배치 -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="기준!"
        android:textSize="15sp"
        android:id="@+id/base"
        android:layout_alignParentRight="true"/>

    <!--base라는 id를 가진 뷰의 왼쪽에 배치 -->
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="왼쪽"
        android:layout_toLeftOf="@id/base"/>
    
</RelativeLayout>

 

**FrameLayout

    => 하위 뷰를 무조건 왼쪽 상단을 기준으로 배치

    => 2개 이상의 하위뷰를 배치하면 겹쳐서 출력

    => 실행중에 addView나 removeView를 이용해서 하위를 추가하거나 삭제 할 수 있음

    => 하위 뷰의 출력속성을 조절해서 보이거나 보이지 않게 할 수 있음

        - visibility라는 속성을 이용하고 View 클래스의 상수로 설정

 

1. FrameLayout으로 이미지 뷰와 버튼을 배치

  1) 출력할 이미지를 res/drawable 에 복사

  2) 레이아웃 파일을 수정

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FrameUse">
<!— 이미지 뷰를 화면에 가득차게 배치 —>
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/tigers"
        android:adjustViewBounds="true"/>

<!— 버튼 추가 —>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="해태 타이거즈"
        android:textSize="30sp"/>


</FrameLayout>

 

**TableLayout

    =>테이블을 만들어서 배치하는 레이아웃

    => TableRow 태그를 이용하여 행을 생성하고 그 안에 위젯을 배치

    => 행의 높이는 무조건 wrap_content

    => 너비는 무조건 match_parent

        - 하나의 셀에 하나의 view만 배치 가능

        - 하나지만 Layout을 배치하면 여러개의 위젯 가능

    => 각셀에 배치되는 위젯의 높이와 너비를 설정하지 않음

 

**GridLayout

    => 테이블 구조로 뷰를 배치

    => layout_columnSpan이나 layout_rowSpan 속성을 이용해서 여러개의 열, 행을 합쳐 하나의 셀 생성 가능

1. 계산기 모양 : LinearLayout과 GridLayout, TableLayout 사용

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Calculator"
    android:orientation="vertical">
    <!-- weight는 비율을 가지고 크기를 결정
    gravity는 내용물의 맞춤 -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="0"
        android:textSize="30dp"
        android:gravity="bottom|right"/>

    <!--하단의 버튼 영역-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <!-- 숫자 영역을 만들어 줄 레이아웃 -->
        <TableLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3">
            <TableRow>
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="7"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="8"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="9"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />

            </TableRow>
            <TableRow>
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="4"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="5"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="6"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />

            </TableRow>
            <TableRow>
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="1"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="2"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="3"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />

            </TableRow>
            <TableRow>
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="."
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="0"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />
                <Button
                    android:layout_weight="1"
                    android:layout_width="0dp"
                    android:text="-"
                    android:paddingTop="27dp"
                    android:paddingBottom="27dp"
                    />

            </TableRow>
        </TableLayout>

        <!-- 연산자 버튼을 배치시킬 레이아웃 -->
        <GridLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <Button
                android:text="C"
                android:paddingTop="18dp"
                android:paddingBottom="18dp"/>
            <Button
                android:text="/"
                android:paddingTop="18dp"
                android:paddingBottom="18dp"/>
            <Button
                android:text="*"
                android:paddingTop="18dp"
                android:paddingBottom="18dp"/>
            <Button
                android:text="+"
                android:paddingTop="21dp"
                android:paddingBottom="21dp"/>
            <Button
                android:text="-"
                android:paddingTop="18dp"
                android:paddingBottom="18dp"/>
            <Button
                android:text="="
                android:paddingTop="18dp"
                android:paddingBottom="18dp"/>



        </GridLayout>
    </LinearLayout>

</LinearLayout>

 

**ConstraintLayout

    => RelativeLayout 처럼 다른 위젯과의 관계를 이용해서 배치하는 옵션이 조금더 다양하고 parent의 위치를 기준으로 배치

    => Margin의 옵션이 다양 : 일반 Margin외에 goneMargin으로 뷰가 사라졌을 때의 마진을 별도로 설정

 

**ScrollView

    => 자식뷰가 부모 뷰보다 큰 경우 그냥 배치시 부모뷰의 영역을 넘어선 부분은 출력되지 않음

        - 스크롤이 가능한 뷰를 만들고 그 안에 자식뷰를 추가해야 함

        - ScrollView는 하나의 자식 뷰만 가짐(여러가지를 보여주고 싶으면 Layout으로 묶어서 표현)

    => 수직 방향의 스크롤이 가능한 뷰이고 좌우 스크롤이 가능한 View는 HorizontalScrollView

    => ListView, MapView, WebView등은  ScrollView의 하위클래스라서 기본적으로 스크롤이 구현되어 있음

        - 이 클래스들은 재사용 가능한 Deque 자료구조를 이용

 

**LinearLayout과 FrameLayout을 이용해서 버튼을 누르면 화면에 출력되는 내용을 변경

    => View를 변경하여 화면 전환

    => 버튼을 3개 배치하고 3개의 화면을 전환

1. 실행가능한 레이아웃을 추가(OverlappingProject)

 

2. 레이아웃 수정

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/btn1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="btn1"/>
        <Button
            android:id="@+id/btn2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="btn2"/>
        <Button
            android:id="@+id/btn3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="btn3"/>
    </LinearLayout>
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/page1"
            android:orientation="horizontal"
            android:background="#ff0000">
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/page2"
            android:orientation="horizontal"
            android:background="#00ff00">
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/page3"
            android:orientation="horizontal"
            android:background="#0000ff">
        </LinearLayout>
    </FrameLayout>
</LinearLayout>

 

3. Activity.java 파일에 인스턴스 변수 선언

    Button btn1, btn2, btn3;
    LinearLayout page1, page2, page3;

 

4. Activity.java 파일의 onCreate메소드에 작성

        //뷰 찾아오기
        btn1 = (Button)findViewById(R.id.btn1);
        btn2 = (Button)findViewById(R.id.btn2);
        btn3 = (Button)findViewById(R.id.btn3);

        page1 = (LinearLayout)findViewById(R.id.page1);
        page2 = (LinearLayout)findViewById(R.id.page2);
        page3 = (LinearLayout)findViewById(R.id.page3);

        //버튼 이벤트 처리
        btn1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                //page1만 출력하고 나머지는 숨기기
                page1.setVisibility(View.VISIBLE);
                page2.setVisibility(View.INVISIBLE);
                page3.setVisibility(View.INVISIBLE);
            }
        });

        //버튼 이벤트 처리
        btn2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                //page1만 출력하고 나머지는 숨기기
                page1.setVisibility(View.INVISIBLE);
                page2.setVisibility(View.VISIBLE);
                page3.setVisibility(View.INVISIBLE);
            }
        });

        //버튼 이벤트 처리
        btn3.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                //page1만 출력하고 나머지는 숨기기
                page1.setVisibility(View.INVISIBLE);
                page2.setVisibility(View.INVISIBLE);
                page3.setVisibility(View.VISIBLE);
            }
        });

 

**TabHost

    => 탭을 만들기 위한 레이아웃

1. 3개의 구조

    - TabHost : 탭 전체 영역

    - TabWidget : 탭 버튼 영역

    - FrameLayout : 탭 버튼을 눌렀을 때 보여질 영역

 

2. 생성

    => TabHost를 이용하여 전체 영역을 생성

    => tabHost 영역 안에 LinearLayout을 이용하여 TabWidget영역을 생성하고 FrameLayout을 생성

    => java 코드에서 TabHost.TabSpec을 생성해서 아이콘 모양을 생성하고 출력할 영역을 지정하여 사용

 

3. 실습 - 3개의 화면을 가진 탭을 설정

<?xml version="1.0" encoding="utf-8"?>

<TabHost
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/host"
    tools:context=".TabUse">
    <!-- 탭 위젯 영역과 콘텐츠 영역의 위치를 설정 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <!-- 탭 위젯 영역 -->
        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"/>
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@android:id/tabcontent">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="TAB ONE"
                android:textSize="30dp"
                android:id="@+id/tab1"/>
            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="TAB TWO"
                android:textSize="30dp"
                android:id="@+id/tab2"/>
            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="TAB THREE"
                android:textSize="30dp"
                android:id="@+id/tab3"/>
        </FrameLayout>

    </LinearLayout>
</TabHost>

 

**SlidingDrawer

    => 핸들을 터치하면 다른 뷰가 펼쳐지듯 아래에서 위로 출력되는 레이아웃

    => handle 속성에 터치할 핸들을 지정하고 content 속성에 펼쳐질 뷰를 설정

    => SlidingDrawer를 만들면 처음에 핸들만 출력되고 핸들을 누르면 content가 출력되고, 출력상태에서 누르면 content가 사라짐

        - 별도의 코드 없이 layout으로 생성

    => 최근에는 이러한 작업을 Dialog를 이용하는 것을 권장

1. 실행가능한 Activity 생성

 

2. layout 수정

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".SlidingUse">
    <SlidingDrawer
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:handle="@+id/handle"
        android:content="@+id/content">
        <ImageView
            android:layout_width="88dp"
            android:layout_height="44dp"
            android:src="@drawable/up"
            android:id="@id/handle"/>
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/box"
            android:id="@id/content"/>
    </SlidingDrawer>

</LinearLayout>

 

**사용자 알림

    => 사용자에게 특수한 상황 발생을 알리는 방법

        - 진동

        - 소리(시스템 사운드, 사용자 사운드)

        - 텍스트(토스트, 스낵바, 대화상자) : 토스트, 스낵바는 시스템 종속적, 대화상자는 애플리케이션 종속

          -> 토스트, 스낵바는 애플리케이션이 종료되어도 출력 가능, 대화상자는 애플리케이션과 같이 종료됨

 

**진동

    => 진동을 사용하려면 퍼미션이 필요

1. 퍼미션 설정시 manifest.xml 파일에서 application 태그 외부에 설정

    => 진동은 <uses-permission android:name="android.permission.VIBRATE"/>

 

2. 진동설정

  1) 1번만 사용

    => Vibrator 변수 = (Vibrator)getSystemService(VIBRATOR_SERVICE);

        - 변수.vibrate(진동시간);  //시간은 1/1000초 단위

  2) 여러번 사용(변수.vibrate(long[], int count);)

    => 첫번째 매개변수는 대기시간과 진동시간의 배열

        - 짝수개로 대입되는데 홀수번째가 대기시간, 짝수번째가 진동시간

    => 두번째 매개변수는 진동 횟수

 

**소리

1. 안드로이드에 내장된 사운드

    - Uri 변수 = RingtoneManager.getDefaultUri(RingtoneManage.TYPE_NOTIFICATION);

      //NOTIFICATION 대신 ALARM이나 RINGTONE 사용가능

    - Ringtone 링톤 = RingtoneManager.getRingtone(getApplicationContext(), 변수);

       링톤.play();

        => 안드로이드에서 getApplicationContext()는 시작하는 Activity의 참조를 리턴

             모든 Activity에서 저 메소드를 호출하면 시작하는 Activity의 참조를 얻어낼수 있음

 

2. 사용자 사운드

    => 사운드를 raw 디렉토리에 저장하여 resource로 만듬

        - MediaPlayer 미디어플레이어 = MediaPlayer.create(Context context, R.raw.사운드ID);

        - 미디어 플레이어.start();

    => Context(=문맥) : 데이터를 저장하고 있는 것을 Context라고 하는데 그림그릴때는 그리기 위한 정보를 저장한 것을 Context라고 함

        - 안드로이드에서 화면에 무엇을 출력하고자 하면 반드시 Context정보가 있어야 함

        - Activity가 Context를 구현한 클래스

        - Context 대신에 Activity를 대입해주면 됨

 

**사운드 실습

1. 사운드 파일을 저장할 raw디렉토리를 res 디렉토리에 생성

    => 안드로이드에서 기본적인 리소스(이미지, 레이아웃, 색상, 스타일, 문자열, 배열등)를 제외한 이진파일은 raw라는 디렉토리에 배치

 

2. raw 디렉토리에 효과음으로 사용할 사운드 파일을 복사

    => buttoneffect.wav

 

3. 진동을 사용하기 위한 권한을 설정

    => manifest.xml 파일에서 application 태그 외부에 작성

    <!-- 진동 사용을 위한 권한 설정 -->
    <uses-permission android:name="android.permission.VIBRATE"/>

 

4. 실행가능한 Activity 추가

 

5. 레이아웃을 수정

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="진동"
        android:id="@+id/btnVibrate"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="시스템 사운드"
        android:id="@+id/btnSysSound"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="사용 사운드"
        android:id="@+id/btnUseSound"/>

</LinearLayout>

                                                                                                                                                                                                            

6. Activity.java 파일의 onCreate 에 작성

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //버튼 3개 찾아오기
        Button btnVibrate = (Button)findViewById(R.id.btnVibrate);
        Button btnSysSound = (Button)findViewById(R.id.btnSysSound);
        Button btnUseSound = (Button)findViewById(R.id.btnUseSound);

        btnVibrate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Vibrator vibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
                vibrator.vibrate(3000);
            }
        });
        btnSysSound.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Uri s1 = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
                //getApplicationContext()는 애플리케이션의 시작 Activity의 참조를 리턴해주는 메소드
                Ringtone ringtone = RingtoneManager.getRingtone(getApplicationContext(), s1);
                ringtone.play();
            }
        });

        btnUseSound.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MediaPlayer player = MediaPlayer.create(MainActivity.this, R.raw.buttoneffect);
                player.start();
            }
        });
    }
}

 

Tip

1. GUI Programming 공부

    => 정수 계산기 -> 소수 계산기 -> 괄호 계산기

 

2. 문자열을 정수로 변환하는 알고리즘

String str = "123";

int result = 0;

for(int i=0; i<str.length; i+=1){

   char ch = str.charAt(i);

   result = result * 10 + (ch-48);

}