마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

안드로이드 bitmap에 대해서 다시 질문드립니다.

0 추천

전에 하나의 글을 이미올렸는대 해결되지 않아서 다시한번 올립니다.

저는 하나의 이미지를 12개로 분할하여 LinkedList에 저장했습니다.

ontouchEvent에서 이미지 두개를 터치하면 두개의 이미지의 위치가 바뀌게 만들려고합니다.

count 변수를 만들어서 2회가 클릭되면 바꾸게 할려고하는대

그 바꾸는 이미지를 어떻게 표현해야될지를몰르겠습니다.

밑에 스크립트처럼 두개의 좌표를 읽고 할려고하는데 여기서 머리가 막막해집니다.

조그마한 도움이라도 주시기바랍니다.

소중한 시간 내주셔서 긴글 읽어주셔서 감사합니다.

@Override
public boolean onTouchEvent(MotionEvent event) {
    int count = 0;
    if(event.getAction() == MotionEvent.ACTION_DOWN)
    {
        count++;
        if(count == 1)
        clickx = (int)event.getX();
        clicky = (int)event.getY();
        if(count == 2){
            clickx1 = (int)event.getX();
            clicky1 = (int)event.getY();
            count = 0;
        }
    }
    return true;
}
익명사용자 님이 2018년 10월 1일 질문

1개의 답변

0 추천

LinkedList에 들은 position을 각각 저장을 해두었다가 2개가 모이면 서로의 위치를 바꿔주면 될 것 같습니다.

바꾼 다음에 화면을 다시 표시해 주면 되겠지요.

update

public class CustomImageView extends AppCompatImageView implements View.OnTouchListener {
    private String TAG = getClass().getSimpleName();

    public CustomImageView(Context context) {
        super(context);
        setOnTouchListener(this);
    }

    public CustomImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        setOnTouchListener(this);
    }

    public CustomImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOnTouchListener(this);
    }

    private ArrayList<Rect> positionList = new ArrayList<>();
    private ArrayList<Bitmap> imageList = new ArrayList<>();

    public void setImage(Bitmap image){

        int w = getResources().getDisplayMetrics().widthPixels;
        int h = getResources().getDisplayMetrics().heightPixels;

        int offset = Math.abs(image.getWidth() - w);
        image = Bitmap.createScaledBitmap(image, image.getWidth() - offset, image.getHeight() - offset, false);
        int sliceW= image.getWidth() / 4;
        int sliceH = image.getHeight()/3;
        for (int i = 0; i < 3; i++) {
            int y = sliceH * i;
            for (int i2 = 0; i2 < 4; i2++) {
                int x = sliceW * i2;
                Rect position = new Rect(x, y, x + sliceW, y + sliceH);
                positionList.add(position);
                imageList.add(Bitmap.createBitmap(image, x, y, sliceW, sliceH));
            }
        }
        invalidate();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        for(int i = 0; i < imageList.size(); i++){
            Rect dst = positionList.get(i);
            Bitmap image = imageList.get(i);
            canvas.drawBitmap(image, new Rect(0, 0, dst.width(), dst.height()), dst, null);
        }
    }

    int position1 = -1;
    int position2 = -1;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN) {
            for(int i = 0; i < imageList.size(); i++){
                if(positionList.get(i).contains((int)event.getX(),(int)event.getY())){
                    if (position1 == -1){
                        position1 = i;
                    } else if (position2 == -1) {
                        position2 = i;
                    }
                    break;
                }
            }
            if (position1 > -1 && position2 > -1) {
                Collections.swap(imageList, position1, position2); //위치를 바꾸는 코드
                position1 = -1;
                position2 = -1;
                invalidate();
            }
            return true;
        }
        return false;
    }
}

말로 설명이 어려워 대충 코드를 짜봤습니다. 잘 해결되면 좋겠네요.

niss (3,110 포인트) 님이 2018년 10월 1일 답변
niss님이 2018년 10월 1일 수정
for (int i = 0; i < 4; i++) {

            l1.add(i , new Rect(w * i / 4, 0, w * (i + 1) / 4, h / 4));
            l1.add(i+4, new Rect(w * i / 4, h / 4, w * (i + 1) / 4, h / 2));
            l1.add(i+8, new Rect(w * i / 4, h / 2, w * (i + 1) / 4, h * 3 / 4));
            l1.add(i+12,new Rect(w * i / 4, h * 3 / 4, w * (i + 1) / 4, h));
}
LinkedList에 담아뒀습니다.
감이안잡히는데 스크립트까지 지도해주실수있으신가요?
이미지를 누르면 리스트에서 Rect에 들어가는걸 찾으세요. 그럼 저 for문에서 저장한 i를 알 수 있으실겁니다. 그럼 그 값을 저장하는거죠. 그래서 i 값이 두개가 모이면 리스트에서 위치를 바꿀 수 있습니다. 그 다음엔 bitmap을 다시 그리시면 됩니다.
@Override
    public boolean onTouchEvent(MotionEvent event) {
        int count = 0;
        if(event.getAction() == MotionEvent.ACTION_DOWN)
        {
            count++;
            for(int i = 0; i < 16; i++){
                l1.get(i);
            }
            
            if(count == 1)
            clickx = (int)event.getX();
            clicky = (int)event.getY();
            if(count == 2){
                clickx1 = (int)event.getX();
                clicky1 = (int)event.getY();
            }
            invalidate();
        }
        return true;
    }
이런식이면되나요?
for (int i = 0; i < 16; i++) {
   if(l1.get(i).contains((int)event.getX(), (int)event.getY())){
     position = i;
     break;
   }
}
이런 식으로 검색을 해야합니다. 이제 카운트는 빼도 되고요. position 변수를 밖에다 전역변수로 두개 선언해 주시고 그 두개에 저장하시면 됩니다.
int position1 = -1
int position2 = -1
이렇게 전역변수를 선언하시고 각각의 변수가 0 이상이 되는지 체크해서 맞으면 그때 바꿔주시면 됩니다. 체크 방법은
if (position1 > -1 && position2 > -1) {
    Collections.swap(l1, position1, position2); //위치를 바꾸는 코드
}
이런식으로 비슷하게 하면 될 것 같습니다.
for (int i = 0; i < 4; i++) {

            l1.add(i , new Rect(w * i / 4, 0, w * (i + 1) / 4, h / 4));
            l1.add(i+4, new Rect(w * i / 4, h / 4, w * (i + 1) / 4, h / 2));
            l1.add(i+8, new Rect(w * i / 4, h / 2, w * (i + 1) / 4, h * 3 / 4));
            l1.add(i+12,new Rect(w * i / 4, h * 3 / 4, w * (i + 1) / 4, h));
}
이부분때문에 실행이안되고 중지되는데
문제가 있는건가요?
저도 몰라서 돌려보니  l1.add(i+4, new Rect(w * i / 4, h / 4, w * (i + 1) / 4, h / 2)); 여기서 에러가 나는데요. 앞에 인덱스를 빼고 돌리세요.

 l1.add(new Rect(w * i / 4, h / 4, w * (i + 1) / 4, h / 2));
이렇게요
@Override
    public boolean onTouchEvent(MotionEvent event) {
        position1 = -1;
        position2 = -1;
        //클릭 체크용
        count = 0;
        if(event.getAction() == MotionEvent.ACTION_DOWN)
        {
            for(int i = 0; i < 16; i++){
                if(l1.get(i).contains((int)event.getX(),(int)event.getY())){
                    count++;
                    position1 = i;
                    position2 = i;
                    break;
                }
            }
            if (position1 > -1 && position2 > -1) {
                Collections.swap(l1, position1, position2); //위치를 바꾸는 코드
                if(count == 2){
                    invalidate();
                    count = 0;
                }
            }

        }
        return true;
    }
이렇게 했는데 위치가 안바뀌네요
@Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN)
        {
            for(int i = 0; i < 16; i++){
                if(l1.get(i).contains((int)event.getX(),(int)event.getY())){
                    if (position1 == -1){
                        position1 = i;
                    } else if (position2 == -1) {
                        position2 = i;
                    }
                    break;
                }
            }
            if (position1 > -1 && position2 > -1) {
                Collections.swap(l1, position1, position2); //위치를 바꾸는 코드
                position1 = -1;
                position2 = -1;
                invalidate();
            }

        }
        return true;
    }

이렇게 해보시겠어요?
해봤는대
바뀌는게
어쩌다한번바뀌고
두개의 위치만변하는게 아닌 전체가 다바뀌네요 ..
그럼 저 위치 바꾸는 코드를 다른걸로 바꿔보세요. Collections로 검색하면 여러가지 나올겁니다.
아무리 찾아도 원인을 모르겠네요..
if (l1.get(i).contains((int) event.getX(), (int) event.getY())) {
여기가 오류더라고요 오류는찾았는대 해결법을몰르겠습니다.
역시 말로는 설명이 어려워서 대충 코드를 짜봤습니다. 제가 한게 원하시는 표현이 맞는지는 모르겠지만 도움이 됐으면 좋겠군요.
class GameView extends RelativeLayout implements View.OnClickListener, Runnable {
    private Bitmap bitmap;
    private Paint paint;
    private Rect[] r, d, ra;
    private Button b;
    private TextView t1, t2;
    private Thread thread;
    private Random rand;
    private LinkedList<Rect> l1 = new LinkedList<>();
    private int index = 0;
    private int position1, position2 = -1;
    private Rect r1;


    public GameView(Context context) {
        super(context);
        setWillNotDraw(false);

        BitmapDrawable drawable = (BitmapDrawable) getResources().getDrawable(R.drawable.image, null);
        bitmap = drawable.getBitmap();

        paint = new Paint();
        thread = new Thread();
        rand = new Random();

        r = new Rect[16];
        d = new Rect[16];
        ra = new Rect[16];
        l1 = new LinkedList<>();

        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        r1 = new Rect(20,150,130,250);
        l1.add(0,new Rect(0, 0, w / 4, h / 4));
        l1.add(1,new Rect(w / 4, 0, w / 2, h / 4));
        l1.add(2,new Rect(w / 2, 0, w * 3 / 4, h / 4));
        l1.add(3,new Rect(w * 3 / 4, 0, w, h / 4));
        l1.add(4,new Rect(0, h / 4, w / 4, h / 2));
        l1.add(5,new Rect(w / 4, h / 4, w / 2, h / 2));
        l1.add(6,new Rect(w / 2, h / 4, w * 3 / 4, h / 2));
        l1.add(7,new Rect(w * 3 / 4, h / 4, w, h / 2));
        l1.add(8,new Rect(0, h / 2, w / 4, h * 3 / 4));
        l1.add(9,new Rect(w / 4, h / 2, w / 2, h * 3 / 4));
        l1.add(10,new Rect(w / 2, h / 2, w * 3 / 4, h * 3 / 4));
        l1.add(11,new Rect(w * 3 / 4, h / 2, w, h * 3 / 4));
        l1.add(12,new Rect(0, h * 3 / 4, w / 4, h));
        l1.add(13,new Rect(w / 4, h * 3 / 4, w / 2, h));
        l1.add(14,new Rect(w / 2, h * 3 / 4, w * 3 / 4, h));
        l1.add(15,new Rect(w * 3 / 4, h * 3 / 4, w, h));

        for (int i = 0; i < 4; i++) {
            r[i] = new Rect(w * i / 4, 0, w * (i + 1) / 4, h / 4);
            r[i + 4] = new Rect(w * i / 4, h / 4, w * (i + 1) / 4, h / 2);
            r[i + 8] = new Rect(w * i / 4, h / 2, w * (i + 1) / 4, h * 3 / 4);
            r[i + 12] = new Rect(w * i / 4, h * 3 / 4, w * (i + 1) / 4, h);

            d[i] = new Rect(20 + (i * 110), 250, 130 + (i * 110), 350);
            d[i + 4] = new Rect(20 + (i * 110), 350, 130 + (i * 110), 450);
            d[i + 8] = new Rect(20 + (i * 110), 450, 130 + (i * 110), 550);
            d[i + 12] = new Rect(20 + (i * 110), 550, 130 + (i * 110), 650);
        }


        t1 = new TextView(context);
        t1.setText("숫자 순서대로 맞추기");
        t1.setTextSize(30);
        t1.setId(View.generateViewId());
        t1.setBackgroundColor(Color.GRAY);
        t1.setGravity(Gravity.CENTER);
        LayoutParams p1 = new LayoutParams(LayoutParams.MATCH_PARENT, 60);
        addView(t1, p1);

        b = new Button(context);
        b.setText("START");
        b.setTextSize(30);
        b.setId(View.generateViewId());
        LayoutParams p2 = new LayoutParams(LayoutParams.MATCH_PARENT, 60);
        p2.addRule(RelativeLayout.BELOW, t1.getId());
        b.setOnClickListener(this);
        addView(b, p2);

        t2 = new TextView(context);
        t2.setText("00:00:00");
        t2.setTextSize(20);
        t2.setId(View.generateViewId());
        t2.setGravity(Gravity.CENTER);
        LayoutParams p3 = new LayoutParams(LayoutParams.MATCH_PARENT, 35);
        p3.addRule(RelativeLayout.BELOW, t1.getId());
        p3.addRule(RelativeLayout.BELOW, b.getId());
        addView(t2, p3);

    }

    @Override
    protected void onDraw(Canvas canvas) {

        for (int i = 0; i < l1.size(); i++) {
            index = rand.nextInt(16);
            ra[i] = r[index];
            canvas.drawBitmap(bitmap, r[index], d[i], paint);
            for (int j = 0; j < i; j++) {
                if (ra[i] == ra[j]) {
                    i--;
                }
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int)event.getX();
        int y = (int)event.getY();
        if(event.getAction() == MotionEvent.ACTION_DOWN)
        {
            for(int i = 0; i < 16; i++){
                if(l1.get(i).contains(x,y)){
                    if (position1 == -1){
                        position1 = i;
                        break;
                    }
                    if(position2 == -1){
                        position2 = i;
                        break;
                    }
                }
            }
            if (position1 > -1 && position2 > -1) {
                Collections.swap(l1, position1, position2); //위치를 바꾸는 코드
                position1 = -1;
                position2 = -1;
                invalidate();
            }
            return true;
        }
        return false;
    }

이렇게 짰는대
contains 부분을 Log.i 로 찍어봤는대
이미지가 아닌부분을 눌러도 true라고 뜨더라고요
지금이것때문에 문제가생겨서 못하고있습니다.
이미지가 아닌 부분을 눌렀는데 true가 나온다면 아마도 l1에 저장된 값이 이미지 너머까지 되어있는 것 같습니다. 화면에 보이는 이미지는 축소되어서 보이고 원본은 화면보다 이미지가 커서 그런지도 몰라요. ImageView의 scaleType을 바꿔서 확인해 보세요.
제가 imageView를 쓰는게 아니라 View에다가 그리는거라서
원본의 크기고 딱맞췄는데 크기문제는 아닌것같습니다.
contains 해주는 리스트를 다른걸로 바꿔보세요. d라던가요. 그래도 안된다면 더 이상은 저도 모르겠군요.
마지막 하나만 더물어보겠습니다.
@Override
    public boolean onTouchEvent(MotionEvent event) {
        int checkcount = 0;
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            ++checkcount;
            if(checkcount == 1){
                for(int i = 0; i < l1.size(); i++){
                    if(l1.get(i).width() == (int)event.getX() && l1.get(i).height() == (int)event.getY()){
                        position1 = i;
                        Log.i("aa", "aa " + i);
                    }
                }
            }
            if(checkcount == 2){

                for(int i = 0; i < l1.size(); i++){
                    if(l1.get(i).width() == (int)event.getX() && l1.get(i).height() == (int)event.getY()){
                        position2 = i;
                        checkcount = 0;
                    }
                }
            }

            if (position1 > -1 && position2 > -1) {
                Collections.swap(l1, position1, position2);
                position1 = -1;
                position2 = -1;
                invalidate();
            }
        }
        return true;
    }

이렇게 새로짰는대
저기 if문에 보면 l1.get(i).width 를 하면 제가 설정한 l1 리스트에 들어있는 모든 width값이 해당되는게 아닌가요?
Log.i로 i를 찍어봤는대 클릭해보니 아무것도 안나오더라고요
l1.get(i).width() == (int)event.getX()
이렇게 하시면 값이 일치해야만 합니다. 하지만 손가락으로 터치해서 완벽하게 좌표를 찝을 수는 없죠.

그래서 Rect().contains(x, y) 로 체크하는 겁니다. Rect()는 사각형 좌표로 구성되기 때문에 터치좌표가 그 안에 들어가는지 체크해주는거에요.

아니면
l1.get(i).left <= (int)event.getX() || l1.get(i).right >= (int)event.getX()
이런식으로 해야겠죠.

그리고
int checkcount = 0;
는 밖에나 선언해주세요. 안에다 하면 카운트가 쌓이지 않습니다.
또 여쭤봐서 죄송합니다.
문제를 찾았습니다.
위에서 제가 썻던 이미지가 좌표가 0,0에 고정이되있고
저는 그것을 list로 씌웠더니 저런 문제가 나타났습니다.
혹시 처음 bitmap을 제가 원하는 위치에 맞출수가있나요?
초반에 설정을 어떻게 하나요?
li.get(0).left 를 log로 찍어봤는대 0이나오더라고요
이미지가 가장먼저 생성되는 좌표가 0,0인데 거기에 맞춰지더라고요
그래서 int w = bitmap.getwidth(); 이부분이로 가져올때
좌표를
0으로 가져오고싶은데 설정방법을몰릅니다.
onDraw 메소드에서 쓰신
canvas.drawBitmap(bitmap, r[index], d[i], paint);
이 부분이 비트맵을 그리는 부분이니까요. d[i] 데이터의 좌표가 최종적으로 그려지는 부분입니다. 이 부분의 좌표를 잘 구성하시면 됩니다.
...