모바일앱개발 강좌

모바일앱개발 강좌 #09 - style작성 후 새로운 테마작성하기, 투명테마 적용하기, 투명한 팝업화면 띄우기, 10초 카운트다운 타이머 생성하기, TextView의 글씨 굵게하기, 가운데 정렬하기, 10초 카운트다운 표시하기, 카운트 다운 종료시 팝업화면 종료하기

두결앱개발 2025. 10. 24. 06:55
반응형
SMALL

 

안녕하세요~ 두결입니다.

 

지난시간에는 팝업화면의 타이틀바를 없애고 뒤로가기 버튼을 막고, 뷰 바깥영역 터치시 강제로 막기를 해보았습니다.

그리고, 팝업화면에서 버튼을 추가해서 팝업화면을 종료까지 시켜보았습니다.

 

이번시간에는 팝업화면을 투명하게 해보고, 카운트다운 타이머를 이용해서 숫자 카운트다운하는 것을 구현해보도록 하겠습니다.

 


▣  style작성 후 새로운 테마작성하기

 

먼저, 팝업화면을 투명하게 해보겠습니다.

 

<activity
    android:name=".Popup"
    android:exported="false"
    android:theme="@style/Theme.AppCompat.Dialog" />
<activity

 

위 코드는 AndroidMaifest.xml 중에 지난시간에 추가한 코드입니다.

새로 띄운 화면을 Dialog 테마, 즉 팝업화면 테마로 바꾼것입니다.

 

이 테마를 바꾸면 화면자체를 투명하게 바꿀수가 있습니다.

안드로이드 스튜디오에서는 투명한 테마를 제공해주지 않기때문에 저희가 직접 스타일을 새로 만들어야 합니다.

 

 

좌측의 프로젝트 창에서 

app->res->values에서 오른쪽버튼!

New -> Values Resource File을 선택!!

 

 

File 명을 style이라고 하고 OK!!

 

 

그러면, 위와같이 빈 style.xml파일이 하나 생성이 됩니다.

 

 

res->values 폴더 밑에 style.xml도 잘 생성되어 보이네요..

 

자, 이제 style.xml안에 새로운 테마를 하나 만들겠습니다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Theme.AppCompat.PopupTransparent" parent="Theme.AppCompat.Dialog">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">#00E2F0D9</item>
    </style>
</resources>

 

<style 에서 이름은 "Theme.AppCompat.PopupTransparent"라고 지정하였습니다.

Theme.AppCompat.의 뒤에 이름은 아무렇게나 작성하시면 됩니다.

저는 PopupTransparent라고 임의로 정하였습니다.

 

그리고, parent = "Theme.AppCompat.Dialog"라고 하였는데요.. 

이렇게 부모로 설정하면 Dialog의 기본 스타일을 그대로 가져와서 적용할수 있습니다.

 

그다음에

<item 에는 부모의 기본 Dialog 속성이외에 추가하거나 변경하고 싶은 항목을 넣어주면 됩니다.

저희는 투명하게 만들예정이니까

투명속성하고 배경색 2가지를 설정하였습니다.

 

android:windowIsTranslucent는 화면을 투명 또는 반투명하게 만드는 XML속성으로 true값을 주면 됩니다.

그리고, 

android:windowBackground는 화면의 배경으로 사용할 리소스를 지정하는 속성인데 리소스 말고도 단순히 색상만 지정해주면 배경색을 바꿀수 있습니다.

 

여태까지 색상을 바꿀때는 

findViewById(R.id.main).setBackgroundColor(Color.parseColor("#ABCDEF"));

이런식으로 "#ABCDEF" 6자리 16진수 값으로 주었는데요

 

여기에서는

#00E2F0D9 이런식으로 8자리 16진수 값을 주었습니다. 

이때 제일 앞에 2자리는 투명도입니다.

00으로 하면 완전 투명이고

FF로 하면 완전 불투명입니다.

반투명은 00 ~ FF 사이의 값으로 조정하면됩니다.

 

 


▣  투명테마 적용하기, 투명한 팝업화면 띄우기

 

자, 이렇게 스타일을 만들었으면

AndroidManifest.xml에서 테마를 지정해주면 됩니다.

 

<activity
    android:name=".Popup"
    android:exported="false"
    android:theme="@style/Theme.AppCompat.Dialog" />

 

이부분을

 

<activity
    android:name=".Popup"
    android:exported="false"
    android:theme="@style/Theme.AppCompat.PopupTransparent" />

 

위와같이 Theme.AppCompat.PopupTransparent로 테마를 지정해주면 됩니다.

 

실행하기전에 

Popup.java에서 설정한 배경색 변경하는 코드는 삭제하겠습니다.

 

findViewById(R.id.main).setBackgroundColor(Color.parseColor("#ABCDEF"));

 

위 부분입니다. 이코드는 삭제하구요~

 

 

한번 실행해보겠습니다.

 

 

네, 위와같이 투명화면이 되었네요...

완전 투명이라 배경색상이 큰 의미는 없긴하네요..

 

반투명으로 한번 해보겠습니다.

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Theme.AppCompat.PopupTransparent" parent="Theme.AppCompat.Dialog">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">#88E2F0D9</item>
    </style>

</resources>

 

style.xml입니다.

windowBackground속성에서 첫2개의 16진수값을 #88로 해보았습니다.

이정도면 50% 투명도가 되겠네요~

 

한번 실행해보겠습니다.

 

네, 위와같이 하니까 투명화면이 되었는지 확인이 잘되네요..^^

 

 

 


▣  10초 카운트다운 타이머 생성하기

 

자, 이제 팝업화면에서 10초 카운트다운 타이머를 하나 생성해보겠습니다.

 

카운트다운 타이머는 왕초보 강좌에서 했었죠?

 

https://eun9073.tistory.com/17

 

앱개발 왕초보 강좌 #16 - CountDown Timer란?, CountDown Timer 생성하기, CountDown Timer에서 숫자 카운트다

안녕하세요~ 두결입니다. 지난시간에는 타이머를 이용해서 거북이를 가로끝까지 간다음에 아래로 이동하는것을 해보았고룰렛이미지 회전하는것 까지 해보았습니다. 이번시간에는 타이머의 다

eun9073.tistory.com

 

위 링크 참고해주세요~~^^

 

CountDownTimer countDownTimer = new CountDownTimer(10000,1000) {
    @Override
    public void onFinish() {
        // CountDownTimer가 끝났을때 처리
    }

    @Override
    public void onTick(long l) {
        // 카운트 다운 시 처리                
    }
};
countDownTimer.start();

 

카운트다운 기본 코드입니다.

10초 카운트다운입니다.

 

자, 이제 이 카운트 다운을 표시할 TextView를 하나 추가해보겠습니다.

 

 

위와같이 레이아웃화면에서 TextView를 하나 추가했습니다.

아! 닫기버튼은 필요없으니 삭제하였습니다.

 

<TextView
    android:id="@+id/txtvCountDown"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="10"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.5" />

 

XML코드에서

ID는 txtvCountDown이라고 하였고

text 는 10

위치는 정중앙으로 하였습니다.

 

 

 


▣  TextView의 글씨 굵게하기, 가운데 정렬하기

 

TextView txtv_CountDown = findViewById(R.id.txtvCountDown);
txtv_CountDown.setTextSize(50);
txtv_CountDown.setTypeface(null, Typeface.BOLD);
txtv_CountDown.setGravity(Gravity.CENTER);
txtv_CountDown.setTextColor(Color.parseColor("#FFFFFF"));

 

Popup.java에서

txtv_CountDown객체를 생성하고

글씨크기를 50으로 설정하였습니다.

 

그리고, 글씨 굵게 하고 가운데 정렬하고 색상도 지정해주었습니다.

 

여기에서 글씨 굵게하는 방법하고 가운데 정렬은 처음 나온거라서 잠깐 애기하고 가겠습니다.

 

글씨를 굵게하는 방법은

setTypeface()함수를 사용하면됩니다.

setTypeface()는 TextView의 글꼴을 변경할때 사용되는데 글꼴뿐만아니라 인자값에 Typeface.BOLD라고 해주시면

글씨의 굵기를 설정할수 있습니다.

 

그리고 가운데 정렬은

setGravity()함수를 사용하면됩니다.

setGravity()는 뷰의 위치를 지정해주는 함수입니다.

Gravity.CENTER는 가운데정렬  Gravity.LEFT | Gravity.TOP등 조합해서 사용할수도 있습니다.

 

 

실행해볼까요?

반응형

 

 

네 10이라는 숫자가 아주 크게잘보이네요..^^

 

 

 


▣  10초 카운트다운 표시하기, 카운트 다운 종료시 팝업화면 종료하기

 

자, 이제 팝업화면에서 10초 카운트다운을 표시해보도록 하겠습니다.

 

CountDownTimer countDownTimer = new CountDownTimer(10000,1000) {
    @Override
    public void onFinish() {
        // CountDownTimer가 끝났을때 처리
    }

    @Override
    public void onTick(long l) {
        // 카운트 다운 시 처리
        txtv_CountDown.setText(String.valueOf(l/1000));
    }
};
countDownTimer.start();

 

카운트다운 숫자를 표시하는 방법은 간단합니다.

위와같이

onTick()함수에서

TextView의 setText로 l/1000값을 설정해주면 됩니다.

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Theme.AppCompat.PopupTransparent" parent="Theme.AppCompat.Dialog">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">#00E2F0D9</item>
    </style>
</resources>

 

실행하기전에

style에서 windowBackground값을 완전투명하게 바꾸겠습니다.

 

 

자, 이제 실행해보겠습니다.

 

네 10부터 카운트 다운이 잘 되네요..^^

 

자, 이제 마지막으로 

카운트다운이 끝나면 팝업화면을 종료시켜보도록 하겠습니다.

 

CountDownTimer countDownTimer = new CountDownTimer(10000,1000) {
    @Override
    public void onFinish() {
        // CountDownTimer가 끝났을때 처리
    }

    @Override
    public void onTick(long l) {
        // 카운트 다운 시 처리
        txtv_CountDown.setText(String.valueOf(l/1000));
    }
};
countDownTimer.start();

 

방법은 간단합니다.

카운트다운타이머의

onFinish()함수에서 앱종료 명령인 finish()함수를 호출만 해주면 됩니다.

 

CountDownTimer countDownTimer = new CountDownTimer(10000,1000) {
    @Override
    public void onFinish() {
        // CountDownTimer가 끝났을때 처리
        finish();  // 화면종료!
    }

    @Override
    public void onTick(long l) {
        // 카운트 다운 시 처리
        txtv_CountDown.setText(String.valueOf(l/1000));
    }
};
countDownTimer.start();

 

위와같이 finish()함수만 써주면 되겠죠?

 

 

자, 잘 실행이 되는지 한번 보겠습니다.

 

 

https://youtube.com/shorts/U0mmyqez5gA?feature=share

 

 

 

 

 

 

네.. 10초 카운트다운이 잘 되고 카운트다운이 끝나면 팝업화면이 자동으로 종료가 되네요..^^

 

 

전체 소스입니다. 참고하세요~

 

MainActivity.java

package com.example.popuptest;

import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class MainActivity extends AppCompatActivity {

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

        Toast.makeText(getApplicationContext(), "팝업메세지 잘뜨나?",Toast.LENGTH_SHORT).show();

        Button btn_Exit = findViewById(R.id.btnExit);
        btn_Exit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setTitle("앱 종료!");
                builder.setMessage("앱을 종료하시겠습니까?");

                builder.setPositiveButton("예", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        // 예 버튼 클릭시 동작.
                        finishAndRemoveTask(); // 앱 완전 종료!!
                    }
                });

                builder.setNegativeButton("아니오", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        // 아니오 버튼 클릭시 동작.
                    }
                });

                builder.setCancelable(false);  // 외부터치 안되게.. 다이얼로그 닫기방지
                builder.show();
            }
        });

        Button btn_ShowPopup = findViewById(R.id.btnShowPopup);
        btn_ShowPopup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                    Intent intent = new Intent(getApplicationContext(), Popup.class);
                    startActivity(intent);
            }
        });

        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
    }


}

 

Popup.java

package com.example.popuptest;

import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;

import androidx.activity.EdgeToEdge;
import androidx.activity.OnBackPressedCallback;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class Popup extends AppCompatActivity {

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

        supportRequestWindowFeature(Window.FEATURE_NO_TITLE); // 타이틀바 없애기
        setContentView(R.layout.activity_popup);



        TextView txtv_CountDown = findViewById(R.id.txtvCountDown);
        txtv_CountDown.setTextSize(150);
        txtv_CountDown.setTypeface(null, Typeface.BOLD);
        txtv_CountDown.setGravity(Gravity.CENTER);
        txtv_CountDown.setTextColor(Color.parseColor("#FFFFFF"));


        CountDownTimer countDownTimer = new CountDownTimer(10000,1000) {
            @Override
            public void onFinish() {
                // CountDownTimer가 끝났을때 처리
                finish();  // 화면종료!
            }

            @Override
            public void onTick(long l) {
                // 카운트 다운 시 처리
                txtv_CountDown.setText(String.valueOf(l/1000));
            }
        };
        countDownTimer.start();




        // 뒤로가기 버튼 막기
        OnBackPressedCallback callback = new OnBackPressedCallback(true) {
            @Override
            public void handleOnBackPressed() {
                setEnabled(true); // 뒤로가기 막기
            }
        };
        getOnBackPressedDispatcher().addCallback(this, callback);

        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 뷰 바깥영역 터치시 강제로 막음
        if(event.getAction() == MotionEvent.ACTION_OUTSIDE)
        {
            return false;
        }
        return true;
    }
}

 

style.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Theme.AppCompat.PopupTransparent" parent="Theme.AppCompat.Dialog">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">#00E2F0D9</item>
    </style>
</resources>

 

AndroidManifest.xml

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

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.PopUpTest">
        <activity
            android:name=".Popup"
            android:exported="false"
            android:theme="@style/Theme.AppCompat.PopupTransparent" />
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

activity_popup.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:id="@+id/main"
    android:layout_width="200dp"
    android:layout_height="200dp"
    tools:context=".Popup">

    <TextView
        android:id="@+id/txtvCountDown"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="10"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

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:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnExit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="앱종료"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.8"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.6" />

    <Button
        android:id="@+id/btnShowPopup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="팝업화면 띄우기"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.6"/>
</androidx.constraintlayout.widget.ConstraintLayout>

 

 

자, 이번시간은 여기까지만 하도록 하구요~

 

다음시간에는 메인화면과 팝업화면간에 데이터 주고받기를 한번 해보겠습니다.

 

그럼, 이만~

 

감사합니다. ^^

반응형
LIST

'모바일앱개발 강좌' 카테고리의 다른 글

모바일앱개발 강좌 #11 - EditText란? EditText의 입력값을 화면에 표시하기, Spinner란? Spinner의 값을 화면에 표시하기, Spinner란? Spinner설정하기, Spinner에서 선택한 값을 불러오기 및 화면에 표시하기  (57) 2025.10.27
모바일앱개발 강좌 #10 - 버튼으로 팝업화면 띄우기, ActivityResultLauncher로 화면띄우기, 메인화면에서 팝업화면으로 데이터 보내기, 팝업화면에서 메인에서 보낸 데이터 받아서 표시하기, 팝업화면에서 메인화면으로 데이터 보내기,메인화면에서 팝업화면에서 보낸 데이터 받아서 처리하기  (66) 2025.10.25
모바일앱개발 강좌 #08 - 팝업화면의 타이틀바 없애기, 뒤로가기 버튼 막기, 뷰 바깥영역 터치시 강제로 막기, 팝업화면 종료하기  (82) 2025.10.23
모바일앱개발 강좌 #07 - 팝업화면이란?, 팝업으로 띄울 화면 생성하기, 버튼 클릭시 팝업화면 띄우기, Intent란?, startActivity()로 화면 전환하기, 팝업화면 테마설정, 팝업화면 크기 설정, 팝업화면 배경색 설정하기  (57) 2025.10.22
모바일앱개발 강좌 #06 - 종료버튼으로 앱 종료하기, finish()와 finishAndRemoveTask() 함수 사용하기, 종료시 종료확인 다이얼로그 띄우기, 종료확인 다이얼로그에 예, 아니오 추가하기, 대화상자 뜬상태에서 외부터치 안되게 하기  (39) 2025.10.21