안드로이드&IOS 앱 개발자 양성

안드로이드&iOS 앱 개발자 양성(83일차)

HRuler 2020. 8. 4. 14:31
더보기

** Fragment
1. 생성
2. Layout 파일에서는 fragment 태그로 생성하고 class 속성에 1번에서 만든 클래스를 등록한다.
3. 코드로 생성
4. 수명 주기 관련 메소드
5. 제공되는 Fragment
6. Fragment는 태블릿 때문에 등장한 View
7. Fragment는 앱을 구성하는 필수 뷰는 아님
8. 실습

** ViewPager
1. 실행 가능한 Activity를 추가 - PagerActivity
2. 출력할 Fragment를 공급해 줄 Adapter 클래스를 생성
3. PagerAdapter.java 파일의 onCreate 메소드에서 ViewPager 설정

** RecycleView
1. 구성 요소
2. 작성 방법
3. 사용

** Material Design

** DrawLayout
1.material에 대한 의존성 설정
2. 실행 가능한 Activity 추가(NavigationActivity)
3. 프로젝트 안에서 사용할 문자열 상수 2개를 res/values/strings.xml에 등록
4. ListView에 출력할 메뉴를 생성
5. 제공되는 레이아웃 수정
6. Activity 파일에 필요한 인스턴스 변수를 선언
7. Activity 파일의 onCreate 메소드에서 출력
8. Activity 파일에 삼선 버튼을 눌렀을 때 호출되는 메소드를 재정의
9. onCreate 메소드에 메뉴를 눌렀을 때 수행할 코드를 작성

** 안드로이드에서 이벤트 처리
1. 상위 클래스로부터 상속받은 메소드를 오버라이딩 - touch 이벤트
2. Delegate 패턴 - 이벤트 처리 객체를 지정

** 안드로이드에서 외부 라이브러리 이용

** 스마트 폰 SDK에서 모듈의 개념

** Xcode 설치
1. 최신 버전 다운로드
2. 설치 후 처음 실행
3. 최신 버전이 설치가 안되는 경우 : 운영체제 버전이 낮아서인 경우가 많다.
4. 예전 버전을 설치하고자 하는 경우
5. Mac이 없는데 iOS Native App 개발

** Fragment

- API Level 11부터 추가된 뷰

- View이지만 Activity처럼 수명주기를 갖는다.

1. 생성

- Fragment 클래스를 상속받아서 생성한다.

- onCreateView 메소드를 재정의해서 화면에 출력할 View를 리턴해 주어야 한다.

- layout.xml 파일을 만들어서 화면을 만들고 LayoutInflater를 이용해서 전개하는 형태를 많이 사용한다.

2. Layout 파일에서는 fragment 태그로 생성하고 class 속성에 1번에서 만든 클래스를 등록한다.

3. 코드로 생성

- FragmentTransaction 객체를 Fragment 클랫의 beginTransaction 메소드를 호출해서 생성하고 add 메소드를 이용해서 View들을 직접 설정하고 commit을 호출해서 생성한다

- commit 메소드가 화면에 적용하는 메소드이다.

4. 수명 주기 관련 메소드

- onAttach : Fragment가 Activity에 부착될 때 호출되는 메소드

- onCreate : 생성될 때 - 만들어질 때 1번만 호출되는 메소드

- onResume : 화면에 보여질 때 호출되는 메소드 - 활성화될 때 호출되는 메소드

- onPause : 화면에서 제거될 때(안보여질 때) 호출되는 메소드

5. 제공되는 Fragment

- ListFragment : ListView를 포함하는 Fragment

- WebViewFragment : WebView를 포함하는 Fragment

- DialogFragment : Dialog를 포함하는 Fragment

- 위 3가지는 별도의 디자인없이 바로 사용이 가능하다.

6. Fragment는 태블릿 때문에 등장한 View

- 왼쪽에 목록을 보여주고 오른쪽에 목록에서 선택한 항목을 출력하는 것을 구현하기 위해 등장했다.

- 초창기에는 왼쪽 목록에 URL을 출력하고 그 URL을 선택하면 오른쪽에 보여주는 형태의 Application에 많이 제공

7. Fragment는 앱을 구성하는 필수 뷰는 아님

- 디바이스의 크기가 점점 커지고 해상도가 높아지기 때문에 많이 사용한다.

8. 실습

- 웹의 SPA처럼 상단에 메뉴를 배치하고 하단에 출력 영역을 배치한 후 메뉴를 누르면 하단에 서로 다른 콘텐츠를 출력하기

- 이런 모양은 FrameLayout을 이용해서도 구현 가능하다.

   FrameLayout을 이용할 때는 교체하는 개념이 아니고 보이게 하고 안보이게 하는 속성을 이용해서 구현한다.

- 상단에 버튼을 3개 배치해서 버튼을 누를 때마다 ListFragment, DialogFragment, 일반 Fragment를 출력

1) 안드로이드 Application 생성
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"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/list"
            android:text="List 출력"/>
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/dialog"
            android:text="Dialog 출력"/>
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/fragment"
            android:text="Fragment 출력"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/main_container"
        android:orientation="vertical">

    </LinearLayout>

</LinearLayout>

3) 3번째 Fragment 화면으로 사용할 Layout을 생성 - three fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="직접 만든 Fragment"
        android:textSize="32sp"
        android:gravity="center"/>

</LinearLayout>

4) ListFragment로부터 상속받는 클래스를 생성 -OneFragment

- ListFragment는 ListView로부터 상속받은 클래스라고 간주할 수 있고 모든 이벤트 핸들러 메소드가 전부 비어있는 상태로 구현되어 있다.

   메소드만 오버라이딩 하면 이벤트 처리가 전부 구현이 된다.

public class OneFragment extends ListFragment {
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        //상위 클래스의 메소드를 호출
        super.onViewCreated(view, savedInstanceState);
        //출력할 데이터 생성
        String [] oop = {"Encapsulation", "Inheritance", "Polymorphism"};
        //Adapter 생성
        ArrayAdapter <String> adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, oop);
        //어탭터 연결
        this.setListAdapter(adapter);
    }

    @Override   //listView는 이벤트가 발생한 ListView, v는 이벤트가 발생한 항목 뷰, position은 누른 항목의 인덱스, id는 v의 id
    public void onListItemClick(ListView listView, View v, int position, long id) {
        //선택한 데이터 찾아오기
        String item = (String)listView.getAdapter().getItem(position);
        //Toast 출력
        Toast.makeText(getActivity(), itme, Toast.LENGTH_LONG).show();
    }
}

5) MainActivity.java 파일에 인스턴스 변수를 선언

- 버튼 3개

- OneFragment 변수, FragmentManager

    Button btn1, btn2, btn3;
    FragmentManager fm;
    OneFragment oneFragment;

6) MainActivity.java 파일의 onCreate 메소드에서 출력 영역에 oneFragment 출력하는 코드 작성

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

        btn1 = (Button)findViewById(R.id.list);
        btn2 = (Button)findViewById(R.id.dialog);
        btn3 = (Button)findViewById(R.id.fragment);

        //FragmentManager 생성
        fm = getSupportFragmentManager();
        //Fragment 객체 생성
        oneFragment = new OneFragment();
        //화면을 갱신할 준비
        FragmentTransaction tf = fm.beginTransaction();
        tf.addToBackStack(null);
        //main_container 영역에 oneFragment를 출력
        tf.add(R.id.main_container, oneFragment);
        //화면을 갱신
        tf.commit();
    }

7) 두 번째 Fragment로 사용할 Fragment 클래스를 생성

- DialogFragment로 부터 상속을 받는 TwoFragment 클래스

public class TwoFragment extends DialogFragment {
    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        //대화상자 만들기
        //Android에서 대화상자는 메소드 체이닝을 이용해서 생성
        AlertDialog dialog = new AlertDialog.Builder(getActivity()).setIcon(android.R.drawable.ic_dialog_alert)
                .setTitle("대화상자 프래그먼트").setMessage("대화상자를 출력합니다.").setPositiveButton("확인", null)
                .create();
        return dialog;
    }
}

8) 세 번째로 보여질 Fragment 클래스를 생성

- Fragment를 상속받는 클래스 - ThreeFragment

public class ThreeFragment extends Fragment {
    //화면을 만들기 위한 메소드        LayoutInflater : layout.xml의 내용을 View로 만들어주는 클래스
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //뷰를 전개할 때      첫 번째 : 뷰의 아이디       두 번째 : 이 뷰가 놓이게 되는 레이아웃 - 부모 뷰
        // 세 번째 : 자신이 최상위 뷰인지 설정 - 부모 뷰가 될 수 있는지 여부
        return inflater.inflate(R.layout.threefragment, container, false);
    }
}

9) 2개의 인스턴스 변수 추가

    TwoFragment twoFragment;
    ThreeFragment threeFragment;

10) onCreate 메소드에 버튼의 이벤트 핸들러를 작성

//버튼들의 이벤트 처리 객체
        Button.OnClickListener handler = new Button.OnClickListener(){
            //이벤트 처리 메소들의 매개변수 정보를 이용하면 이벤트가 발생한 객체와 그 이벤트 처리를 위해서 필요한 정보를 가져올 수 있다.
            public void onClick(View view){
                switch(view.getId()) {
                    case R.id.list:
                        FragmentTransaction tf = fm.beginTransaction();
                        tf.addToBackStack(null);
                        tf.replace(R.id.main_container, oneFragment);
                        tf.commit();
                        break;
                    case R.id.dialog:
                        //대화상자는 다른 프래그먼트와 교체되는 것이 아니고 프래그먼트 위에 출력되는 것이다.
                        if(twoFragment.isVisible() == false){
                            twoFragment.show(fm, null);
                        }
                        break;
                    case R.id.fragment:
                        FragmentTransaction tf2 = fm.beginTransaction();
                        tf2.addToBackStack(null);
                        tf2.replace(R.id.main_container, threeFragment);
                        tf2.commit();
                        break;
                }
            }
        };
        //버튼에 클릭 이벤트 처리를 위한 핸들러 연결
        btn1.setOnClickListener(handler);
        btn2.setOnClickListener(handler);
        btn3.setOnClickListener(handler);
    }

- 대화상자는 데이터 다운로드 받을 때 받기 전에 메시지 출력하는 용도로 사용하면 유용하다.

   서버에서 데이터를 다운로드 받을 때 다른 작업을 해도 된다고 알리고자 하는 경우나 다운받는 과정을 표시할 때 주로 대화상자를 이용한다.

- 안드로이드에서 여러 개의 페이지를 화면에 구현할 때 Activity를 이용하지 않고 Fragment를 구현하는 경우가 종종 있는데 이 때는 버튼을 사용하기도 하지만 ViewPager와 많이 사용한다.

 

** ViewPager

- 사용자의 손가락을 따라가면 순서대로 좌우 화면이 슬라이드되어 나타나는 구성

- AdapterView라서 Adapter를 구현해야 하는데 Adapter 클래스는 PagerAdapter와 FragmentpageAdapter 2개를 제공

- PagerAdapter는 여러 개의 페이지를 스와이프하기 위한 Adapter

- FragmentPageAdapter는 여러 개의 Fragment를 스와이프하기 위한 Adapter

   FragmentPageAdapter를 사용하기 위해서는 FragmentPageAdapter를 상속받는 클래스를 생성해서 getCount 메소드에서 보여질 Fragment의 개수를 리턴하고 getItem메소드에서 인덱스를 매개변수로 받아서 인덱스에 해당하는 Fragment를 리턴하면 된다.

1. 실행 가능한 Activity를 추가 - PagerActivity

<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager.widget.ViewPager 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=".PagerActivity"
    android:id="@+id/pager">

</androidx.viewpager.widget.ViewPager>

2. 출력할 Fragment를 공급해 줄 Adapter 클래스를 생성

- FragmentPagerAdapter를 상속받는 클래스

public class MyPagerAdapter extends FragmentPagerAdapter {

    //Fragment의 List를 생성
    ArrayList<Fragment> fragments;

    //생성자 - 상위 클래스에 기본 생성자가 없어서 생성
    public MyPagerAdapter(@NonNull FragmentManager fm) {
        super(fm);
        //스와이프로 보여질 프래그먼트 리스트를 생성
        fragments = new ArrayList<>();
        fragments.add(new OneFragment());
        fragments.add(new ThreeFragment());
    }

    //실제 출력될 Fragment를 설정하는 메소드
    @NonNull
    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    //출력할 Fragment 개수를 설정하는 메소드     이 메소드가 리턴한 만큼 다른 메소드를 수행한다.
    @Override
    public int getCount() {
        return fragments.size();
    }
}

3. PagerAdapter.java 파일의 onCreate 메소드에서 ViewPager 설정

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

        //어탭터 생성
        MyPagerAdapter adapter = new MyPagerAdapter((getSupportFragmentManager()));
        ViewPager pager = (ViewPager)findViewById(R.id.pager);
        pager.setAdapter(adapter);
    }

 

** RecycleView

- ListView의 확장된 모델

   Android 5.0에서 추가

1. 구성 요소

1) Adapter : 데이터와 각 항목 구성

2) ViewHolder : 각 항목 구성 뷰의 재활용을 목적으로 만든 클래스

3) LayoutManager : 항목을 배치

4) ItemDecoration : 항목을 꾸미는 클래스
5) ItemAnimation : 아이템이 추가되거나 삭제 및 정렬될 때의 애니메이션 처리를 위한 클래스

2. 작성 방법

1) RecycleView를 준비
2) ViewHolder 클래스를 상속받는 클래스를 생성하여 항목을 디자인

3) Adapter 클래스를 상속받는 클래스를 만들어서 ViewHolder를 지정해서 항목 뷰를 만들도록 하고 데이터 개수를 설정

4) LayoutManager 객체를 만들어서 RecyclerView에 설정

- LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager(높이가 다른 그리드) 등을 이용

5) ItemDecoration을 상속받아서 메소드를 재정의

- onDraw : 항목을 배치하기 전에 호출

- onDrawOver : 항목을 배치한 후에 호출

- getItemOffset : 각 항목을 배치할 때 호출

3. 사용

1) RecyclerView 사용을 위한 의존성을 추가

- 모듈을 선택하고 마우스 오른쪽 버튼을 눌러서 [Open Module Settings]를 선택하고 왼쪽 창에서 dependencies를 선택한 후 라이브러리 위의 + 버튼을 누르고 Library Dependency를 선택하고 recycler를 입력해서 검색

- build.gradle 파일의 dependencies에 직접 추가해도 된다.

2) 실행 가능한 Activity 추가 - RecyclerActivity

3) 추가된 레이아웃 수정

- RecyclerView 1개만 배치

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView 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=".RecyclerActivity"
    android:id="@+id/recycler">

</androidx.recyclerview.widget.RecyclerView>

4) 하나의 항목을 만들 ViewHolder 클래스를 생성

- RecyclerView.ViewHolder로부터 상속

- 항목 뷰를 만들어주는데 이 뷰에서 만든 뷰들은 스크롤할 때 자동으로 재사용한다. 이 재사용 매커니즘 때문에 이 뷰를 RecyclerView라고 한다.

//재사용 가능한 항목 뷰를 위한 클래스
class MyViewHolder extends RecyclerView.ViewHolder{

    public TextView title;

    public MyViewHolder(@NonNull View itemView) {
        super(itemView);
        title = itemView.findViewById(android.R.id.text1);
    }
}

5) 여러 개의 데이터를 출력하는 뷰에 데이터를 공급하고 뷰를 만들어주는 Adapter 클래스를 생성 - RecyclerView.Adapter<ViewHolder>를 상속

//RecyclerView에 항목을 만들어주는 Adapter 클래스
class MyAdapter extends RecyclerView.Adapter<MyViewHolder>{
    //출력할 데이터 리스트 변수
    //Adapter는 넘겨받은 데이터를 가지고 뷰의 개수를 설정하고 출력할 뷰 모양을 만들어주고 그 뷰에 데이터를 출력해주는 클래스
    //Adapter는 Model이 아니다.      스마트 폰에서 모델의 역할은 Activity 혹은 별도의 클래스가 한다.
    //데이터에 변화가 생겼을 때 데이터를 재출력하려면 주입받는 데이터가 있어야 한다.
    List<String> list;
    public MyAdapter(List<String> list){
        this.list = list;
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //항목 뷰를 생성해서 ViewHolder에게 넘겨준다.     안드로이드가 제공하는 뷰를 사용
        View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent,
                false);
        return new MyViewHolder(view);
    }

    //출력할 데이터를 매핑하는 클래스
    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        //현재 위치에 해당하는 데이터를 가져오기
        String item = list.get(position);
        holder.title.setText(item);
    }

    //출력할 행의 개수를 설정하는 메소드
    @Override
    public int getItemCount() {
        return list.size();
    }
}

6) 항목의 세부적인 옵션을 수정하는 ItemDecoration을 생성

- 여기를 잘 설계하면 그룹 별 분류를 할 수 있다.

- RecyclerView.ItemDecoration

//각 항목의 세부적인 옵션을 설정할 클래스
class MyItemDecoration extends RecyclerView.ItemDecoration{
    //항목 뷰가 배치될 때 호출되는 메소드          outRect : 외곽 여백 - margin
    //View : 각 항목 뷰     state : 현재 상태
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        //현재 항목 뷰의 인덱스 찾아오기
        int index = parent.getChildAdapterPosition(view) + 1;
        //Item - category, itemname : category로 정렬
        /*
        Item current = list.get(index);
        Item prev = list.get(index - 1);
        if(current.category.equals(prev.category)){
            outRect.set(20,20,20,60);
        }else{
            outRect.set(20,20,20,20);
        }
         */
        //3개를 출력하고 여백을 조금 더 설정
        if(index % 3 == 0){
            outRect.set(20, 20, 20, 60);
        }else{
            outRect.set(20, 20, 20, 20);
        }
        //여러 개의 데이터를 출력할 때 그룹 별로 여백을 다르게 지정하고자 하면 index로 출력할 데이터를 찾아오고 이전 데이터와의 그룹이 다르면
        //여백이 많이 설정     여러 개의 데이터를 가져올 때 자주 활용하는 컬럼으로 정렬해서 가져오기

        //뷰의 배경색을 설정
        view.setBackgroundColor(0xFFECECE9);
        ViewCompat.setElevation(view, 20.0f);
    }
}

7) onCreate 메소드에서 RecyclerView를 출력

public class RecyclerActivity extends AppCompatActivity {

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

        //RecyclerView 찾아오기
        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recycler);
        ArrayList<String> list = new ArrayList<>();
        list.add("변수");
        list.add("연산자");
        list.add("제어문");
        list.add("배열");
        list.add("클래스");
        list.add("상속과 다형성");
        list.add("인터페이스");
        list.add("내부 클래스");
        list.add("예외처리");
        //레이아웃 설정
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        //어탭터 설정
        MyAdapter adapter = new MyAdapter(list);
        recyclerView.setAdapter(adapter);
        //아이템 데코레이션 설정
        recyclerView.addItemDecoration(new MyItemDecoration());
    }
}

 

** Material Design

- 구글의 디자인 철학

- 2014년 이전까지는 그글은 제품 별로 다른 UI를 채택했는데 2014년에 그글이 그동안 제공해왔던 모든 디자인들을 하나로 통합해서 재편

- 처음에는 support library라는 이름으로 배포했는데 2019년부터 이를 다시 통합해서 androidx 패키지로 제공

- androidx에서는 2018년까지 되던 프로젝트가 tarsdk를 올리면 에러가 나는 경우가 발생한다.

- 자주 사용되는 것들이 NavigationDrawer(DrawLayout을 이용해서 작성), 왼쪽이나 오른쪽에서 리스트 뷰를 숨겨놓고 있다가 어떤 이벤트에 의해서 화면에 출력되는 구조 반응형 웹 디자인에서 메뉴를 숨기는 용도로 사용되던 디자인

- Snackbar : Toast가 메시지를 출력하는 용도로 사용되었는데 Toast는 사용자의 상호 작용에는 사용 못한다.

   메시지를 출력하고 사용자가 선택했을 때 어떤 동작으로 수행할 수 있도록 만든 UI

- Activity 화면에 떠 있는 것처럼 보이는 버튼 : FloatingActionButton

- TabLayout : TabHost를 이용해서 Tab을 구현했는데 스와이프까지 적용할 수 있는 레이아웃

- Toolber : Actionbar가 제공되지만 사용자가 원하는 대로 만들고 보여지도록 할 수 있는 바

- Bar의 크기를 늘려서 이미지 등을 출력할 수 있는 AppBarLayout

- CoordinatorLayout : 뷰 2개의 상호작용에 이용하는 레이아웃

   FloatingActionButton과 Snackbar 또는 AppBar와 ListView나 RecyclerView 등의 작용에 사용

   FloatingActionButton은 하단에 배치하는데 Snackbar가 출력되면 버튼이 안보일 수 있어서 CoordinatorLayout 안에 배치하면 Snackbar가 출력될 때 버튼이 자동으로 위로 올라감

   상단의 바와 스크롤이 가능한 뷰가 같이 존재할 때 상단의 바 때문에 스크롤 가능한 뷰의 높이가 좁아져서 많은 양의 데이터를 출력할 수 없는 경우가 발생한다.

   스크롤이 가능한 뷰를 위로 스크롤 하면 AppBar가 자동으로 숨겨지도록 만들 수 있다.

   Pull To Refresh : 아래로 당겨서 새로고침, Layout으로 제공해서 이 안에 스크롤이 가능한 뷰만 배치하면 된다.

   스크롤을 가장 아래에서 했을 때 업데이트(현재 페이지 이전의 데이터를 가져오는 것)하는 것과 위에서 아래로 내렸을 때 업데이트하는 것은 다르다.

   하단에서 상단으로 올라오는 대화상자 - BottomSheet

   보조적인 입력을 받을 때 BottomSheet를 많이 사용

   모바일에서는 콤보 박스를 사용하는 것보다는 하단에서 Sheet 형태로 올라와서 선택하면 설정되도록 하는 경우가 많다.

 

** DrawLayout

- ListView에 목록을 출력해 놓고 어떤 이벤트를 만나면 왼쪽이나 오른쪽에서 밀려들어오듯이 출력되는 레이아웃

- 스마트 폰의 세로 모드에서 메뉴 역할을 하는 목록을 숨겨두었다가 필요할 때 보여주는 형태로 많이 사용

1. material에 대한 의존성을 설정

2. 실행 가능한 Activity 추가(NavigationActivity)

3. 프로젝트 안에서 사용할 문자열 상수 2개를 res/values/strings.xml에 등록

    <string name="drawer_open">네비게이션 열기</string>
    <string name="drawer_close">네비게이션 닫기</string>

- 처음한번 호출해서 변경없이 사용할 문자열 중에서 정적으로 변경가능성이 있는 것은 Java 코드에 문자열 상수로 설정하지 말고 별도의 파일에 만들어두고 파일에서 읽는 것이 좋다.

4. ListView에 출력할 메뉴를 생성

- res 디렉토리에 menu라는 디렉토리를 만들고 그 안에 xml 파일을 추가해서 생성

- res/menu/menu_drawer.xml 파일로 생성

<?xml version="1.0" encoding="utf-8"?>
<menu
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu_drawer_home"
        android:icon="@android:drawable/ic_menu_directions"
        android:title="HOME"/>
    <item
        android:id="@+id/menu_drawer_message"
        android:icon="@android:drawable/ic_menu_agenda"
        android:title="MESSAGE"/>
</menu>

5. 제공되는 레이아웃 수정

- 전체를 DrawLayout으로 감싸고 그 안에 보여질 View를 생성

- 안에 NavigationView를 추가 : 메뉴 형태로 보여질 뷰이다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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=".NavigationActivity">
    <!--기본 화면에 보여질 레이아웃-->
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="네비게이션 사용"/>
    </RelativeLayout>
    <!-- 보여졌다 안보여졌다 하는 네비게이션을 생성-->
    <com.google.android.material.navigation.NavigationView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:id="@+id/main_draw_view"
        android:layout_gravity="start"
        app:menu="@menu/menu_drawer"/>

</androidx.drawerlayout.widget.DrawerLayout>

6. Activity 파일에 필요한 인스턴스 변수를 선언

    DrawerLayout drawer;
    //메뉴를 토글할 변수
    ActionBarDrawerToggle toggle;
    //현재 메뉴 표시 여부를 저장할 변수
    boolean isDrawOpend;

7. Activity 파일의 onCreate 메소드에서 출력

 

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

        //네비게이션 출력 설정
        drawer = (DrawerLayout)findViewById(R.id.main_drawer);
        //토글 생성
        toggle = new ActionBarDrawerToggle(this, drawer, R.string.drawer_open, R.string.drawer_close);
        //액션 바에 출력
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        toggle.syncState();
    }

- 실행하면 상단에 삼선 버튼이 출력된다.

8. Activity 파일에 삼선 버튼을 눌렀을 때 호출되는 메소드를 재정의

    //삼선 버튼을 눌렀을 때 호출되는 메소드
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        if(toggle.onOptionsItemSelected(item)){
            return false;
        }
        return super.onOptionsItemSelected(item);
    }

- 실행을 다시하면 삼선 버튼을 누를 때마다 목록이 토글 된다.

9. onCreate 메소드에 메뉴를 눌렀을 때 수행할 코드를 작성

- NavigationView의 onNavigationItemSelectedListener로 처리

        //메뉴를 눌렀을 때 수행할 코드를 작성
        NavigationView navigationView = (NavigationView)findViewById(R.id.main_draw_view);
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                //메뉴 아이디를 찾아옴
                int id = item.getItemId();
                if(id == R.id.menu_drawer_home){
                    Toast.makeText(NavigationActivity.this, "홈을 선택", Toast.LENGTH_LONG).show();
                }else{
                    Toast.makeText(NavigationActivity.this, "메시지를 선택", Toast.LENGTH_LONG).show();
                }
                return false;
            }
        });

 

** 안드로이드에서 이벤트 처리

1. 상위 클래스로부터 상속받은 메소드를 오버라이팅 - touch 이벤트

2. Delegate 패턴 - 이벤트 처리 객체를 지정

- 이벤트 처리 객체는 이벤트가 발생하는 뷰의 하위 인터페이스로 생성되어 있다.

1) Activity 클래스에 implements해서 사용

2) 이벤트 연결 메소드 안에 Anonymous 객체를 각각 만들어서 처리

3) Anonymous 객체를 별도로 만들어서 설정

4) click, longClick에 한해서는 레이아웃 파일에서 속성으로 메소드를 지정할 수 있다.

- 다른 개발자가 만든 코드를 볼 때는 버튼의 경우는 레이아웃 파일을 확인하고 Activity 클래스에 다른 인터페이스가 implements 되어 있는지 확인

- 자바 1.7 이상을 사용하는 경우 Anonymous 코드는 람다로 변환될 수 있기 때문에 람다의 기본 형식도 확인

 

** 안드로이드에서 외부 라이브러리 이용

- build.gradle 파일의 dependencies 항목에 추가하면 된다.

   직접 추가하기도 하지만 검색해서 추가하기도 한다.

   직접 추가하는 경우에는 버전의 안정성을 담보할 수 없다.

   직접 추가하는 경우에는 모든 책임을 프로그래머가 져야 한다.

- android.support로 시작하거나 androidx로 시작하는 클래스를 사용할 때는 라이브러리의 의존성을 설정할 때 검색해서 설정해야 한다.

   안드로이드는 새로운 버전이 나올 때마다 새로운 뷰나 API를 추가하기 때문에 새로운 버전에서 앱을 개발할 때 이전 버전의 API를 사용하지 못하는 경우가 많다.

 

** 스마트 폰 SDK에서 모듈의 개념

- 독립적으로 실행될 수 있는 것을 모듈이라고 한다.

- Project(Workspace - 작업 단위) -> Module(Application - 배포 단위) -> Activity(실행 단위)

 

** Xcode 설치

- iOS, Mac OS 앱 개발을 위한 IDE가 Xcode

- Mac에만 설치
- 최신 버전은 운영체제에 버전이 맞아야만 설치가 된다.

   최신 X-Code를 사용하고자 하는 경우에는 운영체제도 최신 버전으로 업데이트해야 한다.

- 앱 스토어가 아니라 developers.apple.com에서 베타 버전을 다운받을 수 있는데 이 버전은 운영체제가 실제 배포될 때는 사용할 수 없다.

1. 최신 버전 다운로드

- App Store에서 Xcode로 검색

- 애플 계정과 비밀번호를 입력해서 다운로드와 설치를 진행

2. 설치 후 처음 실행

- 컴포넌트를 다운받아서 추가

3. 최신 버전이 설치가 안되는 경우 : 운영체제 버전이 낮아서인 경우가 많다.

- 운영체제를 업데이트하고 설치 

4. 예전 버전을 설치하고자 하는 경우

   https://developer.apple.com/downloads/more/

- Xcode 11 버전 아래로는 Swift UI를 할 수 없다.

   Swift UI는 새로 등장한 UI 작성 방법 - 코드로 UI를 작성

5. Mac이 없는데 iOS Native App 개발

- 가상머신(VM Ware)에 Mac OS X를 설치해서 할 수 있다.

   다만 기기 테스트가 안된다.