프로그래밍/안드로이드

안드로이드 - 드래그 섀도우 이미지 변경하기

가카리 2015. 12. 5. 11:40
반응형

 

드래그 섀도우는 드래그 중임을 나타내는 반투명한 이미지이다.

 

드래그를 시작하는 startDrag의 인수로 섀도우 이미지를 생성하는 View.DragShadowBuilder 객체가 전달되며 빌더에 의해 섀도우 이미지가 결정된다.

 

빌더는 다음 2개의 생성자가 있다.

 

    View.DragShadowBuilder(View view)

    View.DragShadowBuilder()

    View getView()

 

view를 인수로 전달하면 뷰와 같은 모양의 섀도우를 생성하며 터치한 곳이 뷰의 중앙에 맞추어진다.

 

생성자로 전달받은 뷰는 언제든지 getView 메소드로 다시 참조할 수 있다. 드래그 대상 뷰의 크기만한 커스텀 섀도우를 그릴 때 뷰의 크기를

 

참조할 수 있고 기타 뷰의 여러 속성을 조사할 수 있다.

 

그러나 디폴트 섀도우는 뷰 외에 별도의 추가 정보를 표시할 수 없으며 터치점이 항상 뷰의 중앙이어서 뷰의 모서리를 드래그할때 약간 어색하다.

 

인수 없는 생성자를 사용하면 대상 뷰를 모르므로 투명한 섀도우를 생성하며 따라서 드래그 중인 뷰가 보이지 않는다.

 

커스텀 섀도우를 만드려면 빌더 클래스를 상속받은 후 다음 메소드를 재정의하여 섀도우를 직접 그려야한다.

 

    void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint)

    void onDrawShadow(Canvas canvas)

 

첫번째 메소드는 섀도우의 크기와 중심점의 자표를 지정한다. 섀도우 이미지를 그릴 때 onDrawShadow 메소드가 호출되며 디폴트 구현은

 

생성자로 받은 뷰를 그리는 것으로 되어 있다. 뷰를 받지 않았거나 직접 그리고 싶다면 인수로 전달된 캔버스 인수에 원하는 그림을 그린다.

 

다음 예제는 노란색 바탕에 빨간색 원으로 드래그 섀도우를 그린다.

 

 

dragshadow.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="match_parent"

    android:layout_height="match_parent" >

<Button

    android:id="@+id/source"

    android:layout_width="100dp"

    android:layout_height="wrap_content"

    android:text="Source" />

<Button

    android:id="@+id/target"

    android:layout_width="100dp"

    android:layout_height="wrap_content"

    android:text="Target" />

</LinearLayout>

 

DragShadow.java

 

package com.example.ch27_dragshadow;

 

import android.app.Activity;

import android.content.ClipData;

import android.content.ClipDescription;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Point;

import android.os.Bundle;

import android.view.DragEvent;

import android.view.View;

import android.widget.Button;

import android.widget.Toast;

 

 

public class DragShadow extends Activity {

    Button btnSource;

    Button btnTarget;

    

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.dragshadow);

        

        btnSource = (Button)findViewById(R.id.source);

        btnSource.setOnLongClickListener(new View.OnLongClickListener() {

            

            @Override

            public boolean onLongClick(View v) {

                // TODO Auto-generated method stub

                //클립데이터를 만듬

                ClipData clip = ClipData.newPlainText("dragtext", "dragtext");

                v.startDrag(clip, new CanvasShadow(v), null, 0);//드래그 시작 커스텀 섀도우 빌더 사용

 

                return false;

            }

        });

      

        btnTarget = (Button)findViewById(R.id.target);

        btnTarget.setOnDragListener(mDragListener);

    }

 

    //커스텀 섀도우 빌더

    class CanvasShadow extends View.DragShadowBuilder{

        int mWidth, mHeight;

        public CanvasShadow(View v){

            super(v);

            mWidth = v.getWidth();//좌표를 가져와서 멤버 변수에 넣어둠.

            mHeight = v.getHeight();//좌표를 가져와서 멤버 변수에 넣어둠.

        }

        

        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint){

            //섀도우의 크기와 중심점의 좌표를 지정하는 메소드임

            shadowSize.set(mWidth, mHeight);//사이즈 지정

            shadowTouchPoint.set(mWidth/3, mHeight/3);//중심점 지정

        }

        

        //섀도우 이미지를 그릴때 메소드가 호출됨

        public void onDrawShadow(Canvas canvas){

            Paint pnt = new Paint();

            pnt.setColor(Color.YELLOW);

            canvas.drawRect(0, 0, mWidth, mHeight, pnt);

            

            Paint pnt2 = new Paint();

            pnt2.setAntiAlias(true);

            pnt2.setColor(Color.RED);

            pnt2.setStrokeWidth(8);

            pnt2.setStyle(Paint.Style.STROKE);//속이빈 도형

            canvas.drawCircle(mWidth/2, mHeight/2, mHeight/2-5, pnt2);//동그라미 그리기

        }

    }

 

View.OnDragListener mDragListener = new View.OnDragListener() {

        

        @Override

        public boolean onDrag(View v, DragEvent event) {

            // TODO Auto-generated method stub

            Button btn;

            //드래그 객체가 버튼인지 확인

            if(v instanceof Button){

                btn = (Button)v;

            }else{

                return false;

            }

            

            

            //이벤트를 받음

            switch(event.getAction()){

            //드래그가 시작되면

            case DragEvent.ACTION_DRAG_STARTED:

                //클립 설명이 텍스트면

                if(event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)){

                    btn.setText("Drop OK");//버튼의 글자를 바꿈

                    return true;

                }else{//인텐트의 경우 이쪽으로 와서 드래그를 받을 수가 없다.

                    return false;

                }

            //드래그가 뷰의 경계안으로 들어오면

            case DragEvent.ACTION_DRAG_ENTERED:

                btn.setText("Enter");//버튼 글자 바꿈

                return true;

            //드래그가 뷰의 경계밖을 나가면

            case DragEvent.ACTION_DRAG_EXITED:

                btn.setText("Exit");//버튼 글자 바꿈

                return true;

            //드래그가 드롭되면

            case DragEvent.ACTION_DROP:

                //클립데이터의 값을 가져옴

                String text = event.getClipData().getItemAt(0).getText().toString();

                btn.setText(text);

                return true;

            //드래그 성공 취소 여부에 상관없이 모든뷰에게

            case DragEvent.ACTION_DRAG_ENDED:

                if(event.getResult()){//드래그 성공시

                    Toast.makeText(DragShadow.this, "Drag & Drop 완료", 0).show();

                }else{//드래그 실패시

                    btn.setText("Target");

                }

                return true;

            }

            return true;

        }

    };

}

 

 

실행 화면

첫 실행 화면 Source버튼을 드래그해서 Target버튼에 두겠다.

Source 버튼을 롱터치하면 다음과 같이 노란색 박스와 빨간색 동그라미가 나온다.

드래그가 뷰의 경계안으로 들어오면 버튼 글자를 Enter로 바꾼다.

드래그를 마치면 다음과 같이 버튼의 텍스트가 dragtext로 변한다.

반응형