Canvas에 View 생성하기

Posted by ITPangPang
2016. 11. 16. 22:24 안드로이드(android)/캔버스(Canvas)


Canvas에 View 생성하기



ㆍ 이번글에서는 많이 사용하는 부분은 아니나

    혹시 필요하신분이 있을까 해서 써보려고합니다.


ㆍ 말 그대로 Canvas 영역에서 TextView나 ImageView등을

    생성해서 컨트롤 하는 방법을 소개하려고 합니다




물론 상황에 따라다릅니다.


Canvas 자체에서 View를 다루는것과

단순히 Canvas 위에 View를 올려서

메인에서 사용하는 방법이 있겠죠


오늘은 전자에 대해 알아보려고 합니다.


사실 후자인 Canvas 위에 View를 올려서

사용하는 방법은 딱히 설명할 부분이

없어서이기도 합니다.


후자는 그냥 Layout에

Relative나 Framelayout으로

CustomView와 원하는 TextView나

ImageView를 올려서 제어하면 되겠죠.


그럼

이제 Canvas를 사용하기 위해

CustomView를 하나 생성해보겠습니다.



일단 CustomView 생성



일단 프로젝트를 키자마자

숨도 쉬지 않고 바로

[CustomView.java]

만들어줍니다



이렇게 생성되겠죠?


그 다음 아래와 같이 View를

extends 한후에 onDraw까지

오버라이드 해줍니다

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

public class CustomView extends View
{
public CustomView(Context context, AttributeSet attrs)
{
super(context, attrs);
}

@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
}
}



위에 gif처럼

빨간줄 뜨면 Alt+Enter 친 후에

import 해주고


그 다음 Alt+Insert 누른후에

onDraw를 오버라이드 해오시면 됩니다.



그 다음

[activity_main.xml]로 가서

CustomView를 배치시키면 되겠죠?


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.tistory.itpangpang.canvasex.MainActivity">

<com.tistory.itpangpang.canvasex.CustomView
android:id="@+id/cv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000" />

</RelativeLayout>


요렇게 match로 넣어보겠습니다.


그 다음

CustomView에

일단 뭐라도 그려보겠습니다.

검은화면만 잇으면 이상하니까..


public class CustomView extends View
{
public CustomView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);

Paint MyPaint = new Paint();
MyPaint.setStrokeWidth(10f);
MyPaint.setStyle(Paint.Style.STROKE);
MyPaint.setColor(Color.WHITE);
Path path = new Path();
path.moveTo(450,500);
path.lineTo(450,500);
path.lineTo(400,600);
path.lineTo(300,600);
path.lineTo(400,700);
path.lineTo(350,800);
path.lineTo(450,700);
path.lineTo(550,800);
path.lineTo(500,700);
path.lineTo(600,600);
path.lineTo(500,600);
path.close();
canvas.drawPath(path,MyPaint);
}
}


이전글에서 아주~

허졉하게 만든 별입니다..




그럼 이제 CustomView에 TextView를 붙이자!


그럼 이제 CustomView에서

제어할 TextView를 하나 만들어보도록

하겠습니다.


일단 당연히 View는

동적으로 만들어야겠죠?

만들어 줍시다!

public class CustomView extends View
{
TextView tv;
MainActivity cnxt;
public CustomView(Context context, AttributeSet attrs)
{
super(context, attrs);
cnxt = (MainActivity)context;
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);

tv = new TextView(cnxt);
tv.setTextColor(Color.parseColor("#FFFFFF"));
tv.setText("안녕 여기는 ITPANGPANG!");


자 먼저 간단하게

new TextView(Context)를

통해서 TextView를 하나 생성했습니다.


그 다음에 뭐 글자색깔이나

텍스트를 박아주면 됩니다.


중요한건 여기서 부터겠죠

생성을 했으나 이대로 앱을

실행시켜보면 아~무 변화가

없습니다.


이것을 CustomView

add 시켜줘야 합니다.


어떻게 add 시켜줘야 할까요?


아무리 찾아봐도 addView는

보이지 않습니다.


우리는 여기서 getParent를

이용해서 올릴 View를 찾아서

그 위에 addView 시켜주면 됩니다.


자 바로 이렇게!

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

tv = new TextView(cnxt);
tv.setTextColor(Color.parseColor("#FFFFFF"));
tv.setText("안녕 여기는 ITPANGPANG!");

RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(lp);
((RelativeLayout) this.getParent()).addView(tv);



드디어 TextView가

Canvas와 한 몸이 되었습니다.



자 이제 원하는대로 컨트롤

하면 됩니다.


먼저 가장 기본인

클릭을 해볼까요?

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

tv = new TextView(cnxt);
tv.setTextColor(Color.parseColor("#FFFFFF"));
tv.setText("안녕 여기는 ITPANGPANG!");

RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(lp);
((RelativeLayout) this.getParent()).addView(tv);

tv.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
Toast.makeText(cnxt, "터치!", Toast.LENGTH_LONG).show();
}
});



아주 잘되죠?



그럼 그 다음은

나름 유용하게 쓰이는

터치를 했을때


그 위치에 View를

옮겨보도록 하겠습니다.


onTouchEvent를 오버라이드해서!

바로 setX, setY로 처리~

(setX, setY는 해당 위치로 View를 박아주는 역할입니다)


@Override
public boolean onTouchEvent(MotionEvent e)
{
switch (e.getAction())
{
case MotionEvent.ACTION_DOWN:
tv.setX(e.getX());
tv.setY(e.getY());
break;
}
return true;
}


이렇게 MotionEvent를

통해서 얻어온 x,y좌표를

setX,Y에 넣어주면 됩니다

(ACTION_DOWN 일때!)



아주 쉽죠?


자 그럼 여기서

위에 짠 코드들에 대해

추가 설명해줘야 할 부분이

있습니다.


위에서는 그냥 보기좋게 하려고

onDraw에 다 때려박았는데


다들 아시다시피 onDraw

invalidate();를 하게 되면

호출됩니다.


그럼 new TextView()에

또 들어오게 되겠죠?

그럼 계속계속 만들어지게 됩니다.


그러므로 경우에 따라서

onDraw에서

생성하지 마시고


public CustomView~

{}

이 쪽에서 만드신 후에

잘 컨츄럴 하시면 됩니다.



그리고 두번째!!

방금 써 본 setX, setY에서

넣게되는 x,y 좌표는 절대좌표입니다


지금이야

CustomView를 전체화면으로

쓰고 있으니, e.getX로 받았을때

좌표가 같지만,


만약

CustomView를 화면의 1/3 또는

뭐 1/4 하고 뭐 가운데로 몰거나

그랬을 경우에는 그 만큼 따로

계산을 해줘야 합니다.


저 같은 경우는

CustomView에 이미지를

넣고 사용하고 있는데

(그 후에 화면 가운데 정렬)


이미지 크기에 따라 View크기가

동적으로 바뀌기 때문에


CustomView의 Width, Height를

구한후에 디바이스 전체크기와의 차이를 구하고

나누기 2를 해서 붙여주고 있습니다.

(나누기 2는 마진이 위아래 또는 좌우 2개이기 때문)


tv.setY(e.getY + ( (디바이스의 Height - CustomView.getHeight) /2 ) );


이런식으로 하든

어떤식으로든 하든

좌표를 맞춰준후에 사용하시면 됩니다.


setX, setY가 아닌

마진으로 때려박는 방법도

괜찮습니다!



뭐 여기까지야

그리 어렵지 않습니다.


상황에 따라 맞춰서 만들어서

쓰는게 힘들죠 ㅎㅎ..


그럼 끝!!!