[서울시 앱 공모전 / 서울시를 이겨라] Guide Splash Activity with Viewpager

2017. 12. 6. 23:53Android

Guide Splash Activity with Viewpager


# GuideSplashActivity.java 생성 및 manifest 수정


SplashActivity가 제일 먼저 실행되고 이후에 '시작하기' 버튼을 누르면 MainActivity로 넘어가게 설정한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.jaehyukshin.welcomeseoulloreview">
 
    <uses-permission android:name="android.permission.INTERNET" />
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
 
        </activity>
        <activity android:name=".GuideSplashActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>
cs




# Guide화면으로 보여질 layout 파일을 추가함


애플리케이션의 기본적인 설명을 해줄 화면을 layout xml 파일로 나눠서 보여줄 예정

ViewPager로 xml Layout 파일을 넘겨가면서 앱 가이드를 볼 수 있게 만들 것임.

예제로 기본 layout 파일 3개를 추가했음.

guide_splash_activity1, guide_splash_activity2, guide_splash_activity3를 추가함




# colors.xml에 색깔 저장 및 dimens.xml에 크기 저장, arrays.xml에 배열 저장


colors.xml 및 dimens.xml, arrays.xml 파일 없으면 values에 리소스 파일 새로 생성하면 됨


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#7BA293</color>
    <color name="colorPrimaryLight">#8BE3CE</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FD8BB1</color>
    <color name="greenNike">#7BA293</color>
    <color name="orangeGolfwang">#FDA293</color>
    <color name="pinkGolfwang">#EECEDF</color>
    <color name="colorPrimaryTranslucent">#CC7BA293</color>
    <color name="orangeGolfwangTranslucent">#CCFDA293</color>
 
    <!-- dots inactive colors -->
    <color name="dot_dark_screen1">@color/white</color>
    <color name="dot_dark_screen2">@color/white</color>
    <color name="dot_dark_screen3">@color/white</color>
    <color name="dot_dark_screen4">@color/white</color>
 
    <!-- dots active colors -->
    <color name="dot_light_screen1">@color/orangeGolfwang</color>
    <color name="dot_light_screen2">@color/orangeGolfwang</color>
    <color name="dot_light_screen3">@color/orangeGolfwang</color>
    <color name="dot_light_screen4">@color/orangeGolfwang</color>
 
    <color name="black">#000000</color>
    <color name="white">#FFFFFF</color>
    <color name="spaceGray">#c0c5ce</color>
</resources>
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="dots_height">30dp</dimen>
    <dimen name="dots_margin_bottom">20dp</dimen>
    <dimen name="img_width_height">120dp</dimen>
    <dimen name="padding_small">4dp</dimen>
    <dimen name="padding_medium">8dp</dimen>
    <dimen name="padding_large">16dp</dimen>
 
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="fab_margin">16dp</dimen>
    <dimen name="image_loader_post_width">450dp</dimen>
</resources>
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <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>
cs




# GuideSplashActivity에 사용될 버튼 모양 drawable에 설정


splash_button_shape.xml 파일 drawable에 추가


가이드 스플래시 화면에서 사용할 버튼을 반투명한 색을 설정하기 위해 설정해놓은 colorPrimaryTranslucent라는 color를 사용함


colorPrimary 색 코드가 #7BA293 RGB 이라면, colorPrimaryTranslucent는 7BA293 앞에 투명도 값 CC(16진수 투명값 %)를 붙여서 투명도를 추가해주면 된다.


colorPrimaryTranslucent #CC7BA293 ARGB


CC 이외에도 투명 %퍼센티지마다의 값을 달리해서 넣어주면 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape>
            <corners android:radius="5dp" />
            <solid android:color="@color/colorPrimaryTranslucent" />
        </shape>
    </item>
    <item>
        <shape>
            <corners android:radius="5dp" />
            <solid android:color="@color/colorPrimaryTranslucent" />
        </shape>
    </item>
</selector>
cs




# guide_splash_activity.xml button background 속성을 drawable에 설정한 splash_button_shape로 설정


1
2
3
4
5
6
7
8
9
10
11
        <Button
            android:id="@+id/btn_start"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|bottom"
            android:layout_marginBottom="50dp"
            android:background="@drawable/splash_button_shape"
            android:text="시작하기"
            android:textColor="@android:color/white"
            android:textStyle="bold"
            android:visibility="invisible"/>
cs




# MyViewPagerAdapter 추가


GuideSplashActivity에서 사용하는 ViewPager를 따로 만들어서 사용

btnStart 버튼을 3개의 가이드 화면에서 마지막 세 번째 화면에만 등장하게 설정해둠


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
    ViewPager.OnPageChangeListener viewPagerPageChangeListener = new ViewPager.OnPageChangeListener() {
 
        @Override
        public void onPageSelected(int position) {
            addBottomDots(position);
 
            if (position == layouts.length - 1) {
                btnStart.setVisibility(View.VISIBLE);
 
            } else {
                btnStart.setVisibility(View.INVISIBLE);
 
            }
        }
 
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
 
        }
 
        @Override
        public void onPageScrollStateChanged(int arg0) {
 
        }
    };
 
    public class MyViewPagerAdapter extends PagerAdapter {
        private LayoutInflater layoutInflater;
 
        public MyViewPagerAdapter() {
        }
 
        @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);
        }
    }
cs




# 가이드 화면 중에서 몇 번째 화면인지 표시하는 Layout Dot 표시하기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 
public class GuideSplashActivity extends Activity {
 
    private LinearLayout dotsLayout;
    private TextView[] dots;
    private int[] layouts;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        dotsLayout = (LinearLayout) findViewById(R.id.layoutDots);
 
        layouts = new int[]{
                R.layout.guide_splash_slide1,
                R.layout.guide_splash_slide2,
                R.layout.guide_splash_slide3 };
 
        // adding bottom dots
        addBottomDots(0);
    }
 
    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++) { //이부분 -1이라고 고침
            dots[i] = new TextView(this);
            //HTML 코드를 가져와서 TextView text로 설정, &#8226는 "•" 이거임 dot이 글자인 것임
            dots[i].setText(Html.fromHtml("&#8226;"));
            //dot 크기 변경
            dots[i].setTextSize(35);
 
            dots[i].setTextColor(colorsInactive[currentPage]);
            dotsLayout.addView(dots[i]);
        }
 
        if (dots.length > 0)
            dots[currentPage].setTextColor(colorsActive[currentPage]);
    }
}
 
cs


Guide 화면으로 사용할 layout 파일을 layouts 배열에 담아두고, 이 layout 갯수에 맞게 dot을 만들어서 표시함

Arrays에 추가한 선택된 layout dot 색 및 선택되지 않은 layout dot 색을 설정해줌

layout dot은 특별한 모양이 있는 것이 아니라, "•" 이 모양을 html 코드로 가져와서 안드로이드에서 표시한 것임.

따라서 특수 기호를 TextView로 나타냈고, 텍스트 크기만 바꾼 것임.

이렇게 생각하면 쉽게 LayoutDot을 만들 수 있다.




# 시작하기 버튼을 누르면 MainActivity 시작


1
2
3
4
    private void launchHomeScreen() {
        startActivity(new Intent(getApplicationContext(), MainActivity.class));
        finish();
    }
cs




# Status bar 색 변경


버전 19는 상태바 색을 변경하는 것이 불가해서 버전 21 이상일 경우 상태바 색을 투명으로 변경해줌


1
2
3
4
5
6
7
8
9
    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);
 
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        }
    }
cs




# 뒤로가기 두 번 눌러야 종료


Toast가 띄워져 있는 상태에서 뒤로가기를 눌러야 앱이 종료되게 만드는 메소드 추가


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    private final long FINISH_INTERVAL_TIME = 2000;
    private long backPressedTime = 0;    
 
    @Override
    public void onBackPressed() {
        long tempTime = System.currentTimeMillis();
        long intervalTime = tempTime - backPressedTime;
 
        if (0 <= intervalTime && FINISH_INTERVAL_TIME >= intervalTime) {
            super.onBackPressed();
            GuideSplashActivity.this.finish();
            System.exit(0);
        }
        else {
            backPressedTime = tempTime;
            Toast.makeText(getApplicationContext(), "'뒤로' 버튼을 한 번 더 누르시면 종료됩니다.", Toast.LENGTH_SHORT).show();
        }
    }
cs









최종 코드

# GuideSplashActivity.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
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 android.widget.Toast;
 
public class GuideSplashActivity extends Activity {
    private final long FINISH_INTERVAL_TIME = 2000;
    private long backPressedTime = 0;
 
    private ViewPager viewPager;
    private MyViewPagerAdapter myViewPagerAdapter;
    private LinearLayout dotsLayout;
    private TextView[] dots;
    private int[] layouts;
 
    Button btnStart;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        // making notification bar transparent
        changeStatusBarColor();
 
        setContentView(R.layout.activity_guide_splash);
 
        viewPager = (ViewPager) findViewById(R.id.view_pager);
        dotsLayout = (LinearLayout) findViewById(R.id.layoutDots);
        btnStart = (Button) findViewById(R.id.btn_start);
 
        layouts = new int[]{
                R.layout.guide_splash_slide1,
                R.layout.guide_splash_slide2,
                R.layout.guide_splash_slide3 };
 
        // adding bottom dots
        addBottomDots(0);
 
        myViewPagerAdapter = new MyViewPagerAdapter();
        viewPager.setAdapter(myViewPagerAdapter);
        viewPager.addOnPageChangeListener(viewPagerPageChangeListener);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                launchHomeScreen();
            }
        });
 
    }
 
    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);
 
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        }
    }
 
    private void launchHomeScreen() {
        startActivity(new Intent(getApplicationContext(), 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++) { //이부분 -1이라고 고침
            dots[i] = new TextView(this);
            dots[i].setText(Html.fromHtml("&#8226;"));
            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 change listener
    ViewPager.OnPageChangeListener viewPagerPageChangeListener = new ViewPager.OnPageChangeListener() {
 
        @Override
        public void onPageSelected(int position) {
            addBottomDots(position);
 
            if (position == layouts.length - 1) {
                btnStart.setVisibility(View.VISIBLE);
 
            } else {
                btnStart.setVisibility(View.INVISIBLE);
 
            }
        }
 
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
 
        }
 
        @Override
        public void onPageScrollStateChanged(int arg0) {
 
        }
    };
 
    public class MyViewPagerAdapter extends PagerAdapter {
        private LayoutInflater layoutInflater;
 
        public MyViewPagerAdapter() {
        }
 
        @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);
        }
    }
 
    @Override
    public void onBackPressed() {
        long tempTime = System.currentTimeMillis();
        long intervalTime = tempTime - backPressedTime;
 
        if (0 <= intervalTime && FINISH_INTERVAL_TIME >= intervalTime) {
            super.onBackPressed();
            GuideSplashActivity.this.finish();
            System.exit(0);
        }
        else {
            backPressedTime = tempTime;
            Toast.makeText(getApplicationContext(), "'뒤로' 버튼을 한 번 더 누르시면 종료됩니다.", Toast.LENGTH_SHORT).show();
        }
    }
}
 
cs


# activity_guide_splash.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true">
 
        <android.support.v4.view.ViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true" />
 
        <LinearLayout
            android:id="@+id/layoutDots"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dots_height"
            android:gravity="center"
            android:layout_gravity="center_horizontal|bottom"
            android:orientation="horizontal"
            android:layout_marginBottom="120dp">
 
        </LinearLayout>
 
        <Button
            android:id="@+id/btn_start"
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|bottom"
            android:layout_marginBottom="50dp"
            android:background="@drawable/splash_button_shape"
            android:text="시작하기"
            android:textColor="@android:color/white"
            android:textStyle="bold"
            android:visibility="invisible"/>
 
    </FrameLayout>
 
</RelativeLayout>
cs




# 샘플 영상





#예제 코드는 Github에서 볼 수 있습니다