그림짝맞추기 앱개발

그림짝맞추기 앱만들기 03 - ImageView Style바꾸기, 4개의 이미지 랜덤으로 배치하기, 10개의 이미지에서 2개의 이미지만 랜덤으로 뽑아와서 배치하기

두결앱개발 2025. 12. 15. 05:47
반응형
SMALL

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

 

지난시간에 그림짝맞추기 앱 프로젝트 생성 및 전체화면으로 띄우기를 해보았고 배경이미지 디자인  및 앱에 배경이미지를 표시하는 것까지 해보았습니다. 그리고,  동적 ImageView생성하여 2개의 이미지를 4개의 그림카드에 표시하는것도 해보았구요~

 

이번시간에는 ImageView 배경 디자인을 좀 해보고, 이미지 위치를 랜덤으로 배치하는 부분 해보도록 하겠습니다.

 


▣  ImageView Style바꾸기

먼저, ImageView의 Style을 바꾸어보겠습니다.

 

지금은 단순히 ImageView에 그림만 표시하였는데요...

이렇게 해도 크게 상관은 없지만 보다 가시성을 높이기위해 테두리나 둥근모서리 같은게 있으면 보다 그림카드 같은 느낌이 나기때문에 그부분을 구현해보겠습니다.

 

쉽게 할수 있는방법은 Style을 정의한후에 background로 Style을 지정해주면 됩니다.

 

 

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

New->Drawable Resource File 선택!

 

 

파일명을 round_border_style이라고 한뒤에 OK!!

 

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape = "rectangle">
    <solid android:color="#FFFFFF" />
    <corners android:radius="5dp" />
    <stroke android:width="2dp" android:color="#322270" />
</shape>

 

shape는 "rectangle"로 해주고

solid Color는 흰색으로 하였습니다.

그리고 corner radius는 5dp로 설정하여 약간 둥근 모서리가 되도록 하였습니다.

마지막으로 stroke의 width는 2dp로 하고 색상은 짙은보라색정도로 설정하였습니다.

 

이제, 이 Style을 동적 ImageView의 Background로 지정해주면 됩니다.

 

for(int i=0;i<MAX_IMAGECOUNT;i++)
{
    ImageView imgvCur = arrayListImage.get(i);
    imgvCur.setImageResource(nArrImageID[i]);
    imgvCur.setId(View.generateViewId());
    imgvCur.setBackgroundResource(R.drawable.round_border_style);
    imgvCur.setPadding(7,7,7,7);

    constraintLayout.addView(imgvCur);

 

동적 ImageView를 생성하는 부분인데요~

setBackgroundResource()로 금방 만든 Style을 지정해주었습니다.

그리고, ImageView의 Style은 둥근사각형이고 그림 이미지는 사각형이다 보니까 

이미지가 꽉차지 않고 살짝 안쪽으로 들어가게 setPadding()으로 여백을 주었습니다.

 

자, 여기까지 한번 실행해보겠습니다.

 

네 이렇게 하니까 그냥 그림만 있는것보단 약간 그림카드 느낌이 나네요..^^

 

 


▣  4개의 이미지 랜덤으로 배치하기

다음으로 4개의 이미지를 랜덤으로 배치해보도록 하겠습니다.

 

지금은 무조건 위에 2개가 같은그림이고 아래쪽 2개가 같은그림이니까 맞추기가 너무 쉽죠?

 

그래서, 4개의 이미지를 랜덤으로 배치해야 합니다.

 

4개의 이미지 위치를 위에서 부터 

0, 1

2, 3

이라고 하면  이 4개의 위치를 랜덤으로 발생시켜보겠습니다.

 

// 리소스의 이미지ID를 배열에 초기화 해주는 함수
private void InitImageArray()
{
    nArrImageID = new int[MAX_IMAGECOUNT];
    nArrImageID[0] = R.drawable.imagepair_01;
    nArrImageID[1] = R.drawable.imagepair_01;
    nArrImageID[2] = R.drawable.imagepair_02;
    nArrImageID[3] = R.drawable.imagepair_02;

    // 이미지 위치 랜덤으로 설정하기
    nArrImagePos = new int[MAX_IMAGECOUNT];
    Random randomPos = new Random();
    for(int i=0;i<MAX_IMAGECOUNT;i++)
    {
        nArrImagePos[i] = randomPos.nextInt(MAX_IMAGECOUNT);
        for(int j=0;j<i;j++)
        {
            if (nArrImagePos[i] == nArrImagePos[j])
            {
                i--;
            }
        }
    }

    for (int i = 0; i < MAX_IMAGECOUNT; i++) {
        Log.d("[이미지위치 배열]", "nArrImagePos[  " + i + " ] = " + nArrImagePos[i]);
    }

}

 

InitImageArray()함수안에 이미지 위치를 랜덤으로 설정하는 부분을 추가하였습니다.

 

먼저 nArrImagePos라는 정수배열을 하나 생성하구요~

for문을 돌려서 0~3사이의 값을 랜덤으로 생성합니다.

그값을 배열에 넣은 뒤에

다시 내부 for문에 와서 이 값이 중복이 되는지 안되는지를 체크해서

중복이 된값이면 i--해서 다시 랜덤값을 받도록 하였습니다.

 

1,2,0,3 이런식으로 위치값이 랜덤이 되어야 하는데

1,2,3,3 이런식으로 중복된 값이 들어가면 안됩니다.

그러면 같은 위치에 2개의 이미지가 들어가기때문에 중복을 피하기 위해서

위에서 처럼 이중for문으로 처리하였습니다.

 

마지막으로 중복없이 랜덤값이 잘 들어갔는지 체크하기 위해서

Log.d()를 이용해서 배열의 값을 출력해보았습니다.

 

실행을 해서

 

 

로그창을 가보시면 

 

위와같이 로그에 nArrImagePos값이 잘 출력이 되었습니다.

3, 0, 2, 1 이런식으로 중복없이 랜덤값이 표시되는 것을 알수 있습니다. ^^

 

다시 또 실행해보면

 

 

이번에는 2,1,3,0 이네요.. ^^

 

자, 이제 이 위치값을 동적 ImageView에 적용만 해주면 됩니다.

 

for(int i=0;i<MAX_IMAGECOUNT;i++)
{
    ImageView imgvCur = arrayListImage.get(i);
    imgvCur.setImageResource(nArrImageID[i]);
    imgvCur.setId(View.generateViewId());
    imgvCur.setBackgroundResource(R.drawable.round_border_style);
    imgvCur.setPadding(7,7,7,7);

    constraintLayout.addView(imgvCur);

 

for문으로 동적 ImageView를 생성하는 부분인데

이중에 setImageResource()해주는 부분에 보면 nArrImageID[i]라고 되어있기때문에

배열의 순서대로 이미지를 설정하는데요 

이부분을 위에서 구한 nArrImagePos배열값으로 설정해주면 됩니다.

 

for(int i=0;i<MAX_IMAGECOUNT;i++)
{
    ImageView imgvCur = arrayListImage.get(i);
    imgvCur.setImageResource(nArrImageID[nArrImagePos[i]]);
    imgvCur.setId(View.generateViewId());
    imgvCur.setBackgroundResource(R.drawable.round_border_style);
    imgvCur.setPadding(7,7,7,7);

    constraintLayout.addView(imgvCur);

 

 

네 위와같이 바꾸어주면 됩니다.

 

잘되는지 실행을 해볼까요?

 

2번 실행을 했는데요...

실행할때마다 이미지 위치가 랜덤으로 변경되서 잘 표시가 되네요..^^

 

 

 


▣  10개의 이미지에서 2개의 이미지만 랜덤으로 뽑아와서 배치하기

마지막으로 한가지만 더해볼까요?

 

지금은 계속 같은 이미지만 나와서 약간 지겨우니까 

이미지를 조금더 늘려보겠습니다.

 

 

네. 위와같이 10개의 이미지를 준비하였습니다.

 

 

imagepair_01 ~ 10.png로 저장하고 프로젝트 리소스에 붙여넣기 하겠습니다.

 

네 리소스에 10개의 이미지가 잘 등록이 되었네요~

 

// 리소스의 이미지ID를 배열에 초기화 해주는 함수
private void InitImageArray()
{
    nArrImageID = new int[MAX_IMAGECOUNT];
    nArrImageID[0] = R.drawable.imagepair_01;   nArrImageID[1] = R.drawable.imagepair_02;
    nArrImageID[2] = R.drawable.imagepair_03;   nArrImageID[3] = R.drawable.imagepair_04;
    nArrImageID[4] = R.drawable.imagepair_05;   nArrImageID[5] = R.drawable.imagepair_06;
    nArrImageID[6] = R.drawable.imagepair_07;   nArrImageID[7] = R.drawable.imagepair_08;
    nArrImageID[8] = R.drawable.imagepair_09;   nArrImageID[9] = R.drawable.imagepair_10;
    
    nCurImageCount = 4;

 

먼저, InitImageArray()함수에서 

10개의 ImageID를 배열에 넣구요 현재 이미지 개수는 4라고 설정하겠습니다.

 

이제 이 10개중에 2개를 랜덤으로 가져오면 됩니다. 

int[] nArrSelectImageID;
final int MAX_IMAGECOUNT = 10;
nArrSelectImageID = new int[nCurImageCount];
Random random = new Random();
int nRandom = 0;
// 총 이미지중에 Random값  현재 게임이미지 개수 / 2 개만 뽑아오기
for(int i=0;i<nCurImageCount/2;i++)
{
    nRandom = random.nextInt(MAX_IMAGECOUNT);
    nArrSelectImageID[i] = nArrImageID[nRandom];
    for(int j=0;j<i;j++)
    {
        if (nArrSelectImageID[i] == nArrSelectImageID[j])
        {
            i--;
        }
    }
}

 

nArrSelectImageID라는 정수배열을 새로 만들구요~

MAX_IMAGECOUNT 는 10으로 하였습니다.

 

1단계에서는 총 이미지가 4개이지만 같은이미지가 있으니 필요한 이미지는 2개면 됩니다.

그래서, for문을 nCurImaegCount/2만큼만 돌리고 

랜덤값은 10중에 임의의 값이 나오도록 하였습니다.

 

그리고, nArrSelectImageID에 랜덤값에 해당하는 이미지 ID값을 넣은 뒤에

이중 for문을 통해서 중복된 값이 없도록 하였습니다.

 

// 동일한 이미지를 2개씩 배열에 복사
for(int i=0;i<nCurImageCount/2;i++)
{
    nArrSelectImageID[i+(nCurImageCount/2)] = nArrSelectImageID[i];
}

 

이렇게 10개중에 2개의 이미지ID를 얻어왔으면

다음으로 동일한 이미지를 복사해서 총 4개의 배열에 값이 들어가도록 설정하였습니다.

 

 

자, 여기까지 한번 실행해보겠습니다.

 

 

네 위와같이 실행할때마다 10개의 이미지중에 랜덤으로 2개가 선택이 되고 

그 2개의 이미지를 복사해서 총 4개의 이미지로 만들었고

마지막으로 4개의 위치도 랜덤으로 설정해서 임의의 그림이 배치되도록 하였습니다. ^^

 

 

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

MainActivity.java

package com.example.dk_imagepair;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.WindowInsetsControllerCompat;

import java.util.ArrayList;
import java.util.Random;

public class MainActivity extends AppCompatActivity {

    int[] nArrImageID;
    int[] nArrSelectImageID;
    final int MAX_IMAGECOUNT = 10;
    ViewGroup.LayoutParams layoutParams;
    ArrayList<ImageView> arrayListImage;
    ConstraintLayout constraintLayout;
    float[] fImagePosX;
    float[] fImagePosY;
    int[] nArrImagePos;
    int nCurImageCount;

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

        // 전체 화면으로 만들기
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // 시스템 바 안보이게 하기
        WindowInsetsControllerCompat windowInsetsController =
                WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView());
        windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());

        // 배경 이미지 설정
        SetBackgroundImage();

        // 리소스의 이미지ID를 배열에 설정
        InitImageArray();

        constraintLayout = findViewById(R.id.main);
        arrayListImage = new ArrayList<>();


        // 동적 ImageView 생성
        CreateImageView();

        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;
        });
    }

    // 배경이미지 설정함수
    private void SetBackgroundImage()
    {
        int[] nArrBackgroundImageID = new int[3];
        nArrBackgroundImageID[0] = R.drawable.background01;
        nArrBackgroundImageID[1] = R.drawable.background02;
        nArrBackgroundImageID[2] = R.drawable.background03;

        Random random = new Random();
        int nSelectBackID = random.nextInt(3);

        findViewById(R.id.main).setBackgroundResource(nArrBackgroundImageID[nSelectBackID]);
    }

    // 리소스의 이미지ID를 배열에 초기화 해주는 함수
    private void InitImageArray()
    {
        nArrImageID = new int[MAX_IMAGECOUNT];
        nArrImageID[0] = R.drawable.imagepair_01;   nArrImageID[1] = R.drawable.imagepair_02;
        nArrImageID[2] = R.drawable.imagepair_03;   nArrImageID[3] = R.drawable.imagepair_04;
        nArrImageID[4] = R.drawable.imagepair_05;   nArrImageID[5] = R.drawable.imagepair_06;
        nArrImageID[6] = R.drawable.imagepair_07;   nArrImageID[7] = R.drawable.imagepair_08;
        nArrImageID[8] = R.drawable.imagepair_09;   nArrImageID[9] = R.drawable.imagepair_10;

        nCurImageCount = 4;

        nArrSelectImageID = new int[nCurImageCount];
        Random random = new Random();
        int nRandom = 0;
        // 총 이미지중에 Random값  현재 게임이미지 개수 / 2 개만 뽑아오기
        for(int i=0;i<nCurImageCount/2;i++)
        {
            nRandom = random.nextInt(MAX_IMAGECOUNT);
            nArrSelectImageID[i] = nArrImageID[nRandom];
            for(int j=0;j<i;j++)
            {
                if (nArrSelectImageID[i] == nArrSelectImageID[j])
                {
                    i--;
                }
            }
        }

        // 동일한 이미지를 2개씩 배열에 복사
        for(int i=0;i<nCurImageCount/2;i++)
        {
            nArrSelectImageID[i+(nCurImageCount/2)] = nArrSelectImageID[i];
        }



        // 이미지 위치 랜덤으로 설정하기
        nArrImagePos = new int[nCurImageCount];
        Random randomPos = new Random();
        for(int i=0;i<nCurImageCount;i++)
        {
            nArrImagePos[i] = randomPos.nextInt(nCurImageCount);
            for(int j=0;j<i;j++)
            {
                if (nArrImagePos[i] == nArrImagePos[j])
                {
                    i--;
                }
            }
        }

        for (int i = 0; i < nCurImageCount; i++) {
            Log.d("[이미지위치 배열]", "nArrImagePos[  " + i + " ] = " + nArrImagePos[i]);
        }

    }

    // 동적으로 ImageView 생성해주는 함수
    private void CreateImageView()
    {
        // ArrayList에 새로운 값 추가
        for(int i=0; i<nCurImageCount; i++)
        {
            ImageView imgvDynamic = new ImageView(getApplicationContext());
            arrayListImage.add(imgvDynamic);
        }

        fImagePosX = new float[nCurImageCount];
        fImagePosY = new float[nCurImageCount];

        fImagePosX[0] = 0.1f; fImagePosY[0] = 0.3f;
        fImagePosX[1] = 0.9f; fImagePosY[1] = 0.3f;
        fImagePosX[2] = 0.1f; fImagePosY[2] = 0.67f;
        fImagePosX[3] = 0.9f; fImagePosY[3] = 0.67f;


        for(int i=0;i<nCurImageCount;i++)
        {
            ImageView imgvCur = arrayListImage.get(i);
            imgvCur.setImageResource(nArrSelectImageID[nArrImagePos[i]]);
            imgvCur.setId(View.generateViewId());
            imgvCur.setBackgroundResource(R.drawable.round_border_style);
            imgvCur.setPadding(7,7,7,7);

            constraintLayout.addView(imgvCur);

            // ImageView의 가로, 세로 크기 설정
            layoutParams = imgvCur.getLayoutParams();
            layoutParams.width = 415;
            layoutParams.height = 510;
            imgvCur.setLayoutParams(layoutParams);

            // ImageView의 위치 설정
            ConstraintSet constraintSet = new ConstraintSet();
            constraintSet.clone(constraintLayout);
            constraintSet.connect(imgvCur.getId(), ConstraintSet.TOP, constraintLayout.getId(), ConstraintSet.TOP, 0);
            constraintSet.connect(imgvCur.getId(), ConstraintSet.LEFT, constraintLayout.getId(), ConstraintSet.LEFT, 0);
            constraintSet.connect(imgvCur.getId(), ConstraintSet.RIGHT, constraintLayout.getId(), ConstraintSet.RIGHT, 0);
            constraintSet.connect(imgvCur.getId(), ConstraintSet.BOTTOM, constraintLayout.getId(), ConstraintSet.BOTTOM, 0);
            constraintSet.setHorizontalBias(imgvCur.getId(), fImagePosX[i]);
            constraintSet.setVerticalBias(imgvCur.getId(), fImagePosY[i]);
            constraintSet.applyTo(constraintLayout);
        }
    }
}

 

 

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

 

다음시간에는 타이머를 이용해서 이미지 5초간 보여주고 그림카드 뒤집기 기능을 해보도록 하겠습니다.

 

그럼, 이만~

 

감사합니다. ^^

반응형
LIST