안드로이드를 개발하다 보면 설명이 필요한 기능이나 권한의 용도를 설명해야 할 때가 있다.
이러한 경우에는 튜토리얼 페이지를 통해 사용자가 쉽게 이해할 수 있도록 도울 수 있다.
그럼 이제 튜토리얼 페이지를 구현해보자.
res -> strings.xml
우선 튜토리얼 페이지에서 사용할 글자를 정의한다.
<resources>
<string name="app_name">TutorialActivity</string>
<!-- 이름을 정의하여 조건에 따라 페이지의 이름을 띄운다. -->
<string name="next">다음</string>
<string name="skip">건너띄기</string>
<string name="start">시작</string>
</resources>
여기서 정의된 글자는 버튼의 글자이며 조건에 따라 글자를 띄울 것이다.
res -> values.xml
다음으로 색을 정의할 것이다.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<!-- 배경색-->
<color name="bg_screen1">#07E940</color>
<color name="bg_screen2">#FFAD03</color>
<color name="bg_screen3">#FF3385</color>
<color name="bg_screen4">#25C8E4</color>
<!-- 선택되지 않은 점(선택 되지 않은 페이지 점) -->
<color name="dot_dark_screen1">#1C7C34</color>
<color name="dot_dark_screen2">#A5662D</color>
<color name="dot_dark_screen3">#A54B6A</color>
<color name="dot_dark_screen4">#2D717A</color>
<!-- 선택된 점(해당 페이지 일 때) -->
<color name="dot_light_screen1">#67FF8C</color>
<color name="dot_light_screen2">#FFCE70</color>
<color name="dot_light_screen3">#FF74A8</color>
<color name="dot_light_screen4">#64E7FF</color>
<array name="array_dot_active">
<item>@color/dot_light_screen1</item>
<item>@color/dot_light_screen2</item>
<item>@color/dot_light_screen3</item>
<item>@color/dot_light_screen4</item>
</array>
<array name="array_dot_inactive">
<item>@color/dot_dark_screen1</item>
<item>@color/dot_dark_screen2</item>
<item>@color/dot_dark_screen3</item>
<item>@color/dot_dark_screen4</item>
</array>
</resources>
정의한 색은 배경색과 페이지를 넘길 때 하단에 생기는 점의 색을 정의했다.
자신이 원하는 색으로 바꿔가며 프로젝트를 수행하면 좋을 것 같다.
layout -> page.xml 생성
레이아웃에서 자신이 튜토리얼에 띄울 페이지를 만든다.
예제에서는 4개를 만들었다.
page1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_screen1"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="메론!"
android:textColor="@android:color/white"
android:textSize="18dp"
android:textStyle="bold"
android:layout_margin="30dp"/>
<ImageView
android:layout_width="250dp"
android:layout_height="250dp"
android:src="@drawable/melon" />
</LinearLayout>
page2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_screen2"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="오렌지!"
android:textColor="@android:color/white"
android:textSize="18dp"
android:textStyle="bold"
android:layout_margin="30dp"/>
<ImageView
android:layout_width="250dp"
android:layout_height="250dp"
android:src="@drawable/orange" />
</LinearLayout>
page3.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_screen3"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="사과!"
android:textColor="@android:color/white"
android:textSize="18dp"
android:textStyle="bold"
android:layout_margin="30dp"/>
<ImageView
android:layout_width="250dp"
android:layout_height="250dp"
android:src="@drawable/apple" />
</LinearLayout>
page4.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_screen4"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="포도!"
android:textColor="@android:color/white"
android:textSize="18dp"
android:textStyle="bold"
android:layout_margin="30dp"/>
<ImageView
android:layout_width="250dp"
android:layout_height="250dp"
android:src="@drawable/grape" />
</LinearLayout>
이제 본격적으로 튜토리얼을 구현하는 코드를 작성해보자.
주석을 잘 확인하면서 작성하면 좋을 것 같다.
MainActivity
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button moveButton;
moveButton = findViewById(R.id.moveButton);
moveButton.setOnClickListener(onClickListener);
// 최초 실행 여부를 판단 ->>>
SharedPreferences pref = getSharedPreferences("checkFirst", Activity.MODE_PRIVATE);
boolean checkFirst = pref.getBoolean("checkFirst", false);
// false일 경우 최초 실행
if(!checkFirst){
// 앱 최초 실행시 하고 싶은 작업
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("checkFirst",true);
editor.apply();
finish();
Intent intent = new Intent(MainActivity.this, TutorialActivity.class);
startActivity(intent);
}
}
Button.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, TutorialActivity.class);
startActivity(intent);
finish();
}
};
}
activity_main.xml
<?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"
android:orientation="vertical">
<Button
android:id="@+id/moveButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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>
TutorialActivity
튜토리얼 페이지를 띄어줄 액티비티를 만든다.
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
public class TutorialActivity extends AppCompatActivity {
private ViewPager viewPager;
private PagerAdapter pagerAdapter;
private LinearLayout dotsLayout;
private TextView[] dots;
private int[] layouts;
private Button btnSkip, btnNext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= 21) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
setContentView(R.layout.activity_tutorial);
viewPager = findViewById(R.id.view_pager);
dotsLayout = findViewById(R.id.layoutDots);
btnSkip = findViewById(R.id.btn_skip);
btnNext = findViewById(R.id.btn_next);
// 변화될 레이아웃들 주소
// 원하는 경우 레이아웃을 몇 개 더 추가
layouts = new int[]{
R.layout.page1,
R.layout.page2,
R.layout.page3,
R.layout.page4
};
// 하단 점 추가
addBottomDots(0);
// 알림 표시줄을 투명하게 만들기
changeStatusBarColor();
pagerAdapter = new PagerAdapter();
viewPager.setAdapter(pagerAdapter);
viewPager.addOnPageChangeListener(viewPagerPageChangeListener);
// 건너띄기 버튼 클릭시 메인화면으로 이동
btnSkip.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(TutorialActivity.this, MainActivity.class));
finish();
}
});
// 조건문을 통해 버튼 하나로 두개의 상황을 실행
btnNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int current = getItem(+1);
if (current < layouts.length) {
// 마지막 페이지가 아니라면 다음 페이지로 이동
viewPager.setCurrentItem(current);
}
else {
// 마지막 페이지라면 메인페이지로 이동
startActivity(new Intent(TutorialActivity.this, MainActivity.class));
finish();
}
}
});
}
// 하단 점(선택된 점, 선택되지 않은 점) 구현
private void addBottomDots(int currentPage) {
dots = new TextView[layouts.length]; // 레이아웃 크기만큼 하단 점 배열에 추가
int[] colorsActive = getResources().getIntArray(R.array.array_dot_active);
int[] colorsInactive = getResources().getIntArray(R.array.array_dot_inactive);
dotsLayout.removeAllViews();
for (int i = 0; i < dots.length; i++) {
dots[i] = new TextView(this);
dots[i].setText(Html.fromHtml("•"));
dots[i].setTextSize(35);
dots[i].setTextColor(colorsInactive[currentPage]);
dotsLayout.addView(dots[i]);
}
if (dots.length > 0)
dots[currentPage].setTextColor(colorsActive[currentPage]);
}
private int getItem(int i) {
return viewPager.getCurrentItem() + i;
}
// 뷰페이저 변경 리스너
ViewPager.OnPageChangeListener viewPagerPageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
addBottomDots(position);
// 다음 / 시작 버튼 바꾸기
if (position == layouts.length - 1) {
// 마지막 페이지에서는 다음 버튼을 시작버튼으로 교체
btnNext.setText(getString(R.string.start)); // 다음 버튼을 시작버튼으로 글자 교체
btnSkip.setVisibility(View.GONE);
}
else {
// 마지막 페이지가 아니라면 다음과 건너띄기 버튼 출력
btnNext.setText(getString(R.string.next));
btnSkip.setVisibility(View.VISIBLE);
}
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
};
// 알림 표시줄을 투명하게 만들기
private void changeStatusBarColor() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
}
}
// 호출기 어댑터
public class PagerAdapter extends androidx.viewpager.widget.PagerAdapter {
private LayoutInflater layoutInflater;
public PagerAdapter() {
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(layouts[position], container, false);
container.addView(view);
return view;
}
@Override
public int getCount() {
return layouts.length;
}
@Override
public boolean isViewFromObject(View view, Object obj) {
return view == obj;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View) object;
container.removeView(view);
}
}
}
activity_tutorial.xml
<?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:showIn="@layout/activity_tutorial">
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- 하단 점이 들어갈 레이아웃-->
<!-- layout_alignParent로 아래에 위치-->
<LinearLayout
android:id="@+id/layoutDots"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:gravity="center"
android:orientation="horizontal">
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:alpha=".5"
android:layout_above="@id/layoutDots"
android:background="@android:color/white" />
<!-- 다음 버튼-->
<!-- layout_alignParent로 아래 오른쪽에 위치-->
<Button
android:id="@+id/btn_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@null"
android:text="@string/next"
android:textColor="@android:color/white" />
<!-- 스킵 버튼-->
<!-- layout_alignParent로 아래 왼쪽에 위치-->
<Button
android:id="@+id/btn_skip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:background="@null"
android:text="@string/skip"
android:textColor="@android:color/white" />
</RelativeLayout>
AndroidMainfest.xml
마지막으로 튜토리얼 액티비티에 타이틀 바를 제거하여 깔끔하게 튜토리얼을 볼 수 있게 한다.
<!-- 깔끔하게 튜토리얼만 보기 위해 타이틀 바를 제거 한다.
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar" -->
위 코드를 모두 작성하고 실행하면 다음 결과 동영상과 같이 나오는 것을 확인할 수 있다.
참고
github
'Develop > Java' 카테고리의 다른 글
[Java] 자바 Android 권한 요청 한번에 처리하기 (4) | 2021.08.07 |
---|---|
[Java] 자바 Android 액티비티나 서비스에서 다른 서비스 종료시키기 (0) | 2021.08.05 |
[Java] 자바 Android UsageStatsManage를 통해 현재 실행중인 앱 확인 (1) | 2021.07.22 |
[AWS] 아마존 웹 서비스 Android + Amazon Cognito 에러 메시지 (0) | 2021.07.21 |
[Java] 자바 Android 다이얼로그(Dialog) 구현 (0) | 2021.07.19 |