본문 바로가기
개발 공부/안드로이드 스튜디오(코틀린)

안드로이드 스튜디오(메뉴탭 만들기)

by momo'sdad 2023. 10. 18.

● 메뉴탭 만들기

1.

2.

3.

4.

메뉴모양 리소스 파일 XML 코드

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/item1"
        android:icon="@android:drawable/sym_action_call"
        android:title="연락처" />
    <item
        android:id="@+id/item2"
        android:icon="@android:drawable/presence_audio_online"
        android:title="인터넷" />
    <item
        android:id="@+id/item3"
        android:icon="@android:drawable/presence_video_online"
        android:title="카메라" />
</menu>

● 각 탭들의 Fragment만들기

ContactFragment

WebFragment

CameraFragment

● 메뉴탭 화면

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".KakaoActivity">

    <FrameLayout
        android:id="@+id/fl"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/btnNav"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    </FrameLayout>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/btnNav"
        android:layout_width="0dp"
        android:layout_height="64dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/kakao_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
  • 메뉴탭 화면의 ID : - fl: 메뉴를 눌렀을 때 출력하는 Layout화면

- btnNav: 버튼들을 누르는 네비게이션뷰 바

● 연락처 화면 fragment

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".ContactFragment">

    <ListView
        android:id="@+id/lvContact"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/btnContact"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/etContact"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="010-"
        android:textSize="20sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/btnContact"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/btnContact"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="추가"
        android:textSize="20sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
  • 메뉴탭-연락처 화면의 ID : - lvContact: 연락처를 추가 했을때 추가되는 리스트 뷰

- etContact: 연락처를 입력하는 텍스트 창

- btnContact: 연락처를 추가하는 버튼

● 인터넷 화면 fragment

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".WebFragment">

    <WebView
        android:id="@+id/wv"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="1dp"
        android:layout_marginTop="1dp"
        android:layout_marginEnd="1dp"
        android:layout_marginBottom="1dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
  • 메뉴탭- 인터넷 화면의 ID : - wv: 인터넷창을 보여주는 web 뷰

● 카메라 화면 fragment

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".CameraFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:id="@+id/textView2"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="카메라 페이지입니다"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • 메뉴탭- 카메라 화면의 ID : - textview: 카메라의 화면을 보여줌.

● 메뉴탭 Activity

package com.example.ex221004;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;

import android.os.Bundle;
import android.view.MenuItem;

import com.example.ex221004.databinding.ActivityKakaoBinding;
import com.google.android.material.navigation.NavigationBarView;

public class KakaoActivity extends AppCompatActivity {

    ActivityKakaoBinding binding;
    // Fragment 선언
    ContactFragment contactFragment;
    WebFragment webFragment;
    CameraFragment cameraFragment;
    FragmentManager fragmentManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityKakaoBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // Fragment들의 객체 생성
        contactFragment = new ContactFragment();
        webFragment = new WebFragment();
        cameraFragment = new CameraFragment();

        // Fragment들을 관리할 FragmentManager 필요
        fragmentManager = getSupportFragmentManager();

        binding.btnNav.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {

                if(item.getItemId() == R.id.item1){
                     changeFragment(contactFragment);
                }
                else if (item.getItemId() == R.id.item2){
                    changeFragment(webFragment);
                }else if (item.getItemId() == R.id.item3){
                    changeFragment(cameraFragment);
                }
                return true; // 각각 버튼 색 바뀜(false->true)
            }
        });
    }
    // onCreate() 끝
    // 접근제한자 리턴타입 메소드이름(매개변수){실행문장}
    public void changeFragment(Fragment fragment){
        fragmentManager.beginTransaction().replace(R.id.fl, fragment).commit();
    }
}

※ Fragment를 사용하기 위해서는 부모 Activity가 필요하다!!

- 부모 Activity-> 메뉴탭 Activity

# Fragment 선언

ContactFragment contactFragment;

WebFragment webFragment;

CameraFragment cameraFragment;

FragmentManager fragmentManager; # Fragment 매니저 선언

# Fragment들의 객체 생성

contactFragment = new ContactFragment();

webFragment = new WebFragment();

cameraFragment = new CameraFragment();

# Fragment들을 관리할 FragmentManager 필요

fragmentManager = getSupportFragmentManager();

# Nav Item을 클릭하면 다른 Fragment로 전환 네비게이션 아이템을 선택을 감지하는 리스너를 설정!!

binding.btnNav.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {

@Override

public boolean onNavigationItemSelected(@NonNull MenuItem item) {

if(item.getItemId() == R.id.item1){ # 연락처 버튼을 눌렀을때 contactFragment 전환

changeFragment(contactFragment);

}

else if (item.getItemId() == R.id.item2){ # 인터넷 버튼을 눌렀을때 webFragment 전환

changeFragment(webFragment);

}else if (item.getItemId() == R.id.item3){ # 카메라 버튼을 눌렀을때 cameraFragment 전환

changeFragment(cameraFragment);

}

return true; # 각각 버튼 색(검은색->빨간색) 눌렀을 때 바뀜(false->true)

)

});

# Fragment 전환하기: 접근제한자 리턴타입 메소드이름(매개변수){실행문장}

public void changeFragment(Fragment fragment){

fragmentManager.beginTransaction().replace(R.id.fl, fragment).commit(); # Fragment 전환 완료

}

● 메뉴탭-ContactFragment Activity

package com.example.ex221004;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;

import com.example.ex221004.databinding.FragmentCameraBinding;
import com.example.ex221004.databinding.FragmentContactBinding;

import java.util.ArrayList;


public class ContactFragment extends Fragment {
    // MainActivity의 binding의 이름은 ActivityKakaoBinding

    FragmentContactBinding binding;
    ArrayList<String> data;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        binding = FragmentContactBinding.inflate(getLayoutInflater());
        View view =binding.getRoot();
        // Inflate the layout for this fragment

        // Inflator
        // XML file을 Java에서 접근가능하도록 객체 변환
        // ViewBinding 기법 사용하기 이전;

        // 3. 아이템 클래스 결정
        data = new ArrayList<>();
        data.add("010-1234-0000");
        data.add("010-9999-8888");
        data.add("010-7777-5555");

        // 4. 어댑터 생성 (페이지 정보, 아이템 디자인, 아이템)
        ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity().getApplicationContext(), R.layout.board_list, data);
        // 5. 어댑터 부착
        binding.lvContact.setAdapter(adapter);
        // 6. Event 추가
        binding.btnContact.setOnClickListener(v -> {
            String contact = binding.etContact.getText().toString();

            // 가장 하드코딩
            boolean check = true;

            for(int i = 0; i < data.size(); i++){
                if(contact.equals(data.get(i))){
                    check = false;
                    break;
                }
            }

            if(check == true){
                data.add(contact);
                adapter.notifyDataSetChanged();
            }

            data.add(contact);
            adapter.notifyDataSetChanged();
        });

        binding.lvContact.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {

                AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
                builder.setTitle("삭제?");
                builder.setMessage("지우시겠습니까?");
                builder.setNegativeButton("Cancel", null);
                builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        data.remove(position);
                        adapter.notifyDataSetChanged();
                    }
                });
                builder.show();
            }
        });
        return view;
    }
}
  • binding = FragmentContactBinding.inflate(getLayoutInflater());

View view =binding.getRoot();

# Inflate the layout for this fragment

  • Inflator

XML file을 Java에서 접근가능하도록 객체 변환

ViewBinding 기법 사용하기 이전;

※ AdapterView 사용법 6단계

1. ListView의 위치 결정

2. 항목뷰(itemView)의 디자인 레이아웃(xml) 작성

3. 아이템 결정

​4. Adapter Class 구현

단, 항목 디자인이 TextView라면 생략 가능!!

왜냐하면, TextView를 구현하는 Adapter Class가 이미 만들어져 있다

이름은 ArrayAdapter

5. Adapter 생성 후 ListView에 부착

어댑터에세 넘겨줘야 할 데이터 3개

1) 페이지 정보 : getApplicationContext()

2) 항목 뷰 디자인 레이 아웃 : R.layout.board_list

3) 아이템 정보 : data

ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.board_list, data);

binding.lvBoard.setAdapter(adapter);

6. ListView에 클릭 리스너, Action들을 추가!

 

3. 아이템 클래스 결정

data = new ArrayList<>(); # 배열 리스트 생성

data.add("010-1234-0000");

data.add("010-9999-8888");

data.add("010-7777-5555");

4. 어댑터 생성 (페이지 정보, 아이템 디자인, 아이템)

ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity().getApplicationContext(), R.layout.board_list, data); #??

5. 어댑터 부착

binding.lvContact.setAdapter(adapter); # list뷰에 어댑터를 넣는다.

 

6. Event 추가

binding.btnContact.setOnClickListener(v -> { # btnContact를 눌렀을때 contact에 입력한 문자(숫자)를 반환

String contact = binding.etContact.getText().toString();

// 가장 하드코딩

boolean check = true;

for(int i = 0; i < data.size(); i++){

if(contact.equals(data.get(i))){ # ? contact의 길이가 data의 길이와 같다면

check = false;

break;

}

}

if(check == true){ #

data.add(contact);

adapter.notifyDataSetChanged();

}

data.add(contact); # data 배열에 contact를 추가

adapter.notifyDataSetChanged(); # notifyDataSetChanged는 리스트의 크기와 아이템이 둘 다 변경되는 경우에 사용

});

  • list뷰에 있는 연락처를 클릭했을때

binding.lvContact.setOnItemClickListener(new AdapterView.OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {

AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); # 팝업띄우기

builder.setTitle("삭제?");

builder.setMessage("지우시겠습니까?");

builder.setNegativeButton("Cancel", null); # Cancel일 결루 아무일도 일어나지 않음

builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { # OK를 눌렀을때

@Override

public void onClick(DialogInterface dialogInterface, int i) {

data.remove(position); # 해당위치의 연락처를 삭제함

adapter.notifyDataSetChanged(); # notifyDataSetChanged는 리스트의 크기와 아이템이 둘 다 변경되는 경우에 사용

}

});

builder.show();

}

● 메뉴탭-WebFragment Activity

package com.example.ex221004;

import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.example.ex221004.databinding.FragmentWebBinding;

public class WebFragment extends Fragment {

    FragmentWebBinding binding;
    WebView wv; // 인터넷 화면을 보여줄 WebView
    WebSettings webSettings;  // WebView의 설정을 담고 있는 객체

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        binding = FragmentWebBinding.inflate(getLayoutInflater());
        View view = binding.getRoot();

        wv = binding.wv;
        webSettings = wv.getSettings();
        webSettings.setSupportZoom(true); 
        webSettings.setJavaScriptEnabled(true); 
        webSettings.setBuiltInZoomControls(true); 
        webSettings.setDomStorageEnabled(true); 
        webSettings.setSupportMultipleWindows(false); 
        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
        webSettings.setCacheMode(webSettings.LOAD_CACHE_ELSE_NETWORK); 
        webSettings.setUseWideViewPort(true); 
        webSettings.setJavaScriptCanOpenWindowsAutomatically(false); 
        webSettings.setLoadWithOverviewMode(true);

        wv.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                wv.loadUrl(url);
                return true;
            }
        });
        wv.loadUrl("http://www.naver.com/");

        return view;
       }
       // onCreate() 끝
}
  • binding = FragmentContactBinding.inflate(getLayoutInflater());

View view =binding.getRoot();

# Inflate the layout for this fragment

  • Inflator

XML file을 Java에서 접근가능하도록 객체 변환

ViewBinding 기법 사용하기 이전;

  • WebView wv; # 인터넷 화면을 보여줄 WebView
  • WebSettings webSettings; # WebView의 설정을 담고 있는 객체

  • wv = binding.wv;

webSettings = wv.getSettings();

webSettings.setSupportZoom(true); // Zoom 사용 여부

webSettings.setJavaScriptEnabled(true); // JavaScript 사용 여부

webSettings.setBuiltInZoomControls(true); // 화면 확대 축소 허용 여부

webSettings.setDomStorageEnabled(true); // 로컬 저장소 사용 여부

webSettings.setSupportMultipleWindows(false); // 멀티윈도우 사용 여부

webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); // 컨텐츠 사이즈 맞추기

webSettings.setCacheMode(webSettings.LOAD_CACHE_ELSE_NETWORK); // 캐시 사용 여부

webSettings.setUseWideViewPort(true); // view port 사용 여부

webSettings.setJavaScriptCanOpenWindowsAutomatically(false); ​// JS가 window.open() 여부

webSettings.setLoadWithOverviewMode(true); // 메타 태그 허용 여부

  • wv.setWebViewClient(new WebViewClient(){ # 페이지 컨트롤을 위한 기본적인 함수, 다양한 요청, 알림을 수신하는 기능을 한다.

@Override

public boolean shouldOverrideUrlLoading(WebView view, String url) {

# 만약 유저가 로딩한 컨텐츠에서 링크를 클릭할 경우에, 어떻게 할지를 override하는 것

-> 잠시 특정 웹사이트 페이지를 유저에게 보여주고, 클릭시에는 크롬같은 브라우저에서 웹서핑을 하도록 한다면, 아래와 같이 startActivity를 구현

wv.loadUrl(url);

return true;

}

});

● 메뉴탭-CameraFragment Activity

package com.example.ex221004;

import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.ex221004.databinding.FragmentCameraBinding;

public class CameraFragment extends Fragment {

    FragmentCameraBinding binding;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        binding = FragmentCameraBinding.inflate(getLayoutInflater());
        View view = binding.getRoot();
        return view;
    }
}
  • binding = FragmentContactBinding.inflate(getLayoutInflater());

View view =binding.getRoot();

# Inflate the layout for this fragment

  • Inflator

XML file을 Java에서 접근가능하도록 객체 변환

ViewBinding 기법 사용하기 이전;

반응형