안드로이드 Canvas, Paint 사용하기




간단하게 말하면 Canvas는 도화지, Paint는 붓이라고 할 수 있습니다.

Paint에서 선의 굵기, 색상, 모양등을 선택해서 다양한 형태로 그릴 수 있습니다.

  • View를 상속받는 Custom클래스를 생성
  • Canvas에 그리고 싶은 내용을 onDraw에 코딩
Paint에서 사용되는 메소드
  • setColor(int color) - Paint의 색상 설정
  • setStrokeWidth(float width) - Paint의 굵기를 설정
  • setStyle(Paint.Style style) - Paint 스타일을 설정
  • setTextSize(float textSize) - Paint의 글자 크기를 설정
  • setAntiAlias(boolean aa) - Paint의 경계면을 부드럽게 처리할지 설정
등등..

Canvas에서 사용되는 메소드
  • void drawRect(left, top, right, bottom) - (left, top) 와 (right, bottom)를 대각선으로 가지는 사각형을 그림
  • void drawText(text, x, y, paint) - (x,y) 좌표에 문자를 출력
  • void drawLine(startX, startY, stopX, stopY, paint) - (x,y) 좌표부터 (x,y) 좌표에 선을 그림
  • void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) - 왼쪽 모서리 좌표를 (x,y)로 가지는  bitmap 을 그림
등등..

public class MyCanvas extends View {

public MyCanvas(Context context) {
super(context);
}

public MyCanvas(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}

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

Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawRect(10, 10, 100, 100, paint);

}

}


Canvas에 이미지 그리기

Bitmap img = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
canvas.drawBitmap(img, 300, 350, paint);


만약 이미지를 작게 또는 크게 그리고 싶을때는 createScaledBitmap을 사용합니다.

Bitmap smallimg = Bitmap.createScaledBitmap(img, img.getWidth()/2, img.getHeight()/2, false);
canvas.drawBitmap(smallimg, 400, 350, paint);

Bitmap bigimg = Bitmap.createScaledBitmap(img, img.getWidth()*2, img.getHeight()*2, false);
canvas.drawBitmap(bigimg, 100, 200, paint);


Touch event 추가하기

-Canvas에 touch event를 추가하려면 onTouchEvent메소드를 Override하고 

 return 값이 false일 경우 touch event를 받지 않겠다는 것이므로 return 값을 true로 해줘야합니다

화면에 터치된 x좌표와 y좌표는 .getX(), getY()를 통해 알 수 있습니다.

getX와 getY의 반환 값은 float이므로 int에 값을 저장하고 싶으면 형변환을 해줘야합니다.

@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
    invalidate();
return true;
}


Mask Filter 추가하기


1) View의 LayerType을 Software로 변경

public MyCanvas(Context context) {
super(context);
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

2) BlurMaskFilter를 생성해서 Paint 요소에 적용

- 첫번째 인자는 Blur의 정도 두번째 인자는 Blur를 줄 타입입니다.

BlurMaskFilter blur = new BlurMaskFilter(100,
BlurMaskFilter.Blur.INNER);
mPaint.setMaskFilter(blur);



아래 예제는 Canvas, Paint, 더블 버퍼링을 사용한 예제입니다.

코드는 깃허브에서 볼 수 있습니다.

https://github.com/Ywook/AndroidPractice10


      


    



안드로이드 파일 입출력 예제


파일 입출력을 할 때 내장 메모리 파일을 처리하는 경우와 외장 메모리(SD card) 파일을 처리하는 경우가 있습니다.



안드로이드에서 Byte 단위 처리를 할 때는 

  • FileInputStream/FileOutputStream
  • BufferedInputStream/BufferedoutputStream


문자 단위 처리 할 때는

  • FileReader/FileWiter
  • BufferedReader/BufferedWriter

클래스를 사용합니다.


내장 메모리 파일 처리


내장 메모리 파일 쓰기

- 아래 코드에서 FileWriter의 첫 번째 인자인 getFilesDir()는 파일이 저장되는 디렉토리를 나타내는 경로입니다.

  두 번째 인자가 true일 경우 기존 파일이 존재할 경우 이어쓰기를 하고 false일 경우 기존 파일이 존재할 경우 덮어쓰기를 합니다.

try{
BufferedWriter bw = new BufferedWriter(new FileWriter(getFilesDir() + "test.txt", true));
bw.write("안녕하세요 Hello");
bw.close();

Toast.makeText(this,"저장완료", Toast.LENGTH_SHORT).show();
}catch (Exception e){
e.printStackTrace();
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}


내장 메모리 파일 읽기

-  FileReader의 첫 번째 인자로 읽을 파일의 경로를 지정해줍니다.

readLine() 메소드는 줄 단위로 읽기 때문에 while문을 사용해서 끝까지 읽도록 해야합니다. 

try{
BufferedReader br = new BufferedReader(new FileReader(getFilesDir()+"test.txt"));
String readStr = "";
String str = null;
while(((str = br.readLine()) != null)){
readStr += str +"\n";
}
br.close();

Toast.makeText(this, readStr.substring(0, readStr.length()-1), Toast.LENGTH_SHORT).show();

}catch (FileNotFoundException e){
e.printStackTrace();
Toast.makeText(this, "File not Found", Toast.LENGTH_SHORT).show();
}catch (IOException e) {
e.printStackTrace();
}


외장 메모리 파일 처리(SD cared)


외장 메모리에 파일을 쓰기 위해서는 Permission이 필요합니다.
API 23 마시멜로 버전부터는 권한이 일반권한(Normal Permission)위험권한(Dangerous Permission)으로 나뉘게됐습니다.
위험 권한은 Permission 이외에도 별도의 권한을 요청하는 코드를 작성해야합니다.
외장 메모리 파일 쓰기는 위험 권한으로 지정되어 있습니다.

먼저 manifest에서 permission 코드를 작성합니다.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

아래 checkFunction()이 실행되면서 외부 메모리에 파일을 쓸 권한이 있는지 체크합니다.
이때 requestPermissions가 권한을 요청하는 팝업창을 띄우는 역할을 합니다.

onRequestPermissionsResult Override 메소드는 해당 권한의 사용자 수락 여부를 확인하는 메소드입니다.

public void checkFunction(){
int permissioninfo = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(permissioninfo == PackageManager.PERMISSION_GRANTED){
Toast.makeText(this,"SDCard 쓰기 권한 있음",Toast.LENGTH_SHORT).show();
}else{
if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)){
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},100);

}else{
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},100);
}
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
String str = null;
if(requestCode == 100){
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
str = "SD Card 쓰기권한 승인";
else str = "SD Card 쓰기권한 거부";
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
}
}


외장 메모리 경로 불러오기
-외장 메모리의 경로는 기기마다 다르게 인식할 수 있기 때문에  절대 경로로 지정해줘야합니다. 

getExternalPath()는 외장 메모리 경로를 반환해주는 메소드입니다.
Environment.MEDIA_MOUNTED는 외장 메모리가 존재하고 읽고 쓰기가 가능한 상태를 나타냅니다.
만약 저 상태가 아닐경우 내장 메모리의 경로를 반환합니다.

public String getExternalPath(){

    String sdPath ="";
String ext = Environment.getExternalStorageState();
if(ext.equals(Environment.MEDIA_MOUNTED)){
sdPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/";
}else{
sdPath = getFilesDir() +"";

}
return sdPath;
}

외장 메모리 파일 처리

-외장 메모리 파일 처리는 내장 메모리 파일 처리하는 경우와 비슷합니다.


파일읽기

try{
String path = getExternalPath();
BufferedReader br = new BufferedReader(new FileReader(path+title));
String readStr = "";
String str = null;
while(((str = br.readLine()) != null)){
readStr += str +"\n";
}
br.close();


}catch (FileNotFoundException e){
e.printStackTrace();
Toast.makeText(this, "File not Found", Toast.LENGTH_SHORT).show();
}catch (IOException e) {
e.printStackTrace();
}

파일쓰기

try{
String path = getExternalPath();
String filename = title;

BufferedWriter bw = new BufferedWriter(new FileWriter(path + filename, false));
bw.write("Hello");
bw.close();
Toast.makeText(this,"저장완료", Toast.LENGTH_SHORT).show();
}catch (Exception e){
e.printStackTrace();
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}


아래 예제는 파일 입출력을 사용한 예제입니다.


  


  


  



위 예제의 모든 코드는 깃허브에서 볼 수 있습니다.

https://github.com/Ywook/AndroidPractice9


안드로이드 웹 파일 저장 및 통신



안드로이드 스튜디오에 웹 파일을 추가하려면 Android mode에서 app을 오른쪽 버튼 클릭을 하고 아래와 같은 방법으로

assets 폴더를 생성합니다.


그리고 assets 폴더에 추가할 웹 파일을 저장합니다.

웹 파일을 추가할 때는 Android resource file이 아닌 File을 클릭해서 추가해야합니다.



assets 폴더에 추가한 웹 파일을 웹뷰에서 불러오는 방법입니다.

이 예제에서는 assets폴더의 www폴더를 만들고 www폴더 웹 파일을 추가했기 때문에 /www/urladd.html 경로를 사용했습니다.

webView.loadUrl("file:///android_asset/www/urladd.html");


추가한 웹 파일과 앱간의 JavaScript를 이용하여 통신하려면 통신할때 사용할 클래스를 생성해야합니다.

class JavaScriptMethod{
@JavascriptInterface
public void addSite(String url, String title){
for(int i = 0 ; i < data.size(); i++){
if(data.get(i).getUrl().equals(url)){
handler.post(new Runnable() {
@Override
public void run() {
webView.loadUrl("javaScript:displayMsg()");
}
});
return;
}
}
Sitedata temp = new Sitedata(url, title);
data.add(temp);
titles.add(temp.toString());
adapter.notifyDataSetChanged();
}
@JavascriptInterface
public void showUrl(){
handler.post(new Runnable() {
@Override
public void run() {
linear.setVisibility(View.VISIBLE);
}
});
}
}

그리고 webView.addJavascriptInterface(new JavaScriptMethod(), "myApp")를 추가하면 아까 만들었던 JavaScriptMethod 클래스를 웹 파일에서 myApp이라는 이름으로 사용할 수 있게 됩니다.


만약 웹 파일에 있는 JavaScript로 만들어진 function을 액티비티에서 호출하려면 아래와 같은 방법을 사용합니다.

이 때 웹 파일에 displayMsg()라는 function이 선언되어 있어야합니다.

webView.loadUrl("javaScript:displayMsg()");


아래 예제는 웹 파일 저장 및 통신, 애니메이션을 사용한 예제입니다.

    


    


위 예제의 모든 코드는 깃허브에서 볼 수 있습니다.

https://github.com/Ywook/AndroidPractice8


+ Recent posts