Androidアプリで画面サイズに依存しないcm指定の入出力

多くのAndroidアプリは画面サイズが変われば表示されるアプリの大きさも変わります。
しかし、（稀だとは思いますが）アプリによっては画面サイズに関わらず1cmの大きさなら1cmの大きさの入出力をしなければならない場合があると思います。

先日、私が作った曲線定規というアプリでは実際のサイズの入出力が必要でしたのでその時に使った方法を紹介します。


![曲線定規.png](https://qiita-image-store.s3.amazonaws.com/0/98758/eb40441a-9747-5a33-ed7a-0a3df5e542e4.png)
曲線定規


このアプリでは、まず背景が1cm四方の四角形になっています。
画面が大きくなったからといって1cm四方が崩れては定規として成り立たなくなってしまいます。
画面のサイズに依存しない描画が求められています。
また、画面をなぞって線を書くとその線の長さも表示されます。



#**1cm四方の正方形を描く方法**

まず背景に四角を描画します。
わたしはこちら（[http://android.keicode.com/basics/ui-canvas-simple-rect.php](http://android.keicode.com/basics/ui-canvas-simple-rect.php)）を参考にしました。



##**MainActivity.java**

```java:MainActivity.java
import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {
　　@Override protected void onCreate(Bundle savedInstanceState) {
　　　super.onCreate(savedInstanceState);
　　　setContentView(new CanvasTest1View(this));
　　}
}
```


##**CanvasTest1View.java**
```java:CanvasTest1View.java
public class CanvasTest1View extends View {
    private Rect rect;
    private Paint paint;
    public CanvasTest1View(Context context) {
        super(context);
        rect = new Rect();
        paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);//直線
        paint.setStrokeWidth(10);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawRect(rect, paint);
        rect.set(10, 10, 200, 200);
        invalidate();
    }

}
```




![2.png](https://qiita-image-store.s3.amazonaws.com/0/98758/1e8bca8b-bbf1-2beb-aa40-7c352bef3119.png)

rect.set(10, 10, 200, 200);
をループなどを使い複数実行することで方眼を作ることができます。
今書かれている四角は縦横２００ピクセルの四角となっています。
ピクセルとは機種ごとの大きさになっていて、
極端に言うと400×400ピクセルの四角い画面を持ったandroidがあったとすれば
画面の1/4をこの四角が占めるということになります。

今回は1cmの四角を書いていきたいので1cmが何ピクセルか調べる必要があります。
1cmが何ピクセルかを調べるにはまずdpiを求めなければなりません。
dpiとはドットパーインチの略で、１インチの直線を書くのに何ピクセルを必要とするかという単位です。

まず、端末の1dpiを調べます
public float dpi = main.getResources().getDisplayMetrics().densityDpi;

最近はxxhdpiを採用している端末が多いので
dpiには480が入ることが多いと思います。
つまり、1インチ（2.54cm)は480ピクセルということになります。
ということは、
480/2.54=188.976378
約188.9ピクセルが1cmということになります。
これを踏まえてソースを変更します。

まず、1cmが何ピクセルか調べるクラスを作成します。


##**CalcDpi.java**

```java:CalcDpi.java
import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {
　　@Override protected void onCreate(Bundle savedInstanceState) {
　　　super.onCreate(savedInstanceState);
　　　setContentView(new CanvasTest1View(this));
　　}
}
```

先ほど書いたソースを変更してCalcDpiを使用します。



##**MainActivity.java**

```java:MainActivity.java
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new CanvasTest1View(this,this));
    }
}
```


##**CanvasTest1View.java**

```java:CanvasTest1View.java
import android.graphics.Color;
import android.view.View;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;

public class CanvasTest1View extends View {
    private Rect rect;
    private Paint paint;

    private CalcDpi calcdpi;

    public CanvasTest1View(Context context,MainActivity main) {
        super(context);
        rect = new Rect();
        paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);//直線
        paint.setStrokeWidth(10);

        calcdpi = new CalcDpi(main);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawRect(rect, paint);

        rect.set(10, 10, (int)calcdpi.getPxTocm(),(int)calcdpi.getPxTocm());
        invalidate();
    }
}
```

![3.png](https://qiita-image-store.s3.amazonaws.com/0/98758/715c7fcb-b761-63a3-3a2c-d52f05bcafee.png)

あまり違いはわかりませんがw
1cmの四角形を描画することができました。



#**入力した幅をcm単位で取得する方法**
次に画面をなぞった長さをcmで取得する方法を説明します。
参考にしたサイトはコチラ
http://android.keicode.com/basics/ui-canvas-path.php
です。
先ほどと同じかたの記事です。Oyama氏感謝します。

dpi→cmは先ほどのCalcDpiクラスを流用します。
MainActivityもそのままです。


##**CanvasTest2View.java**

```java:CanvasTest2View.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class CanvasTest2View extends View {
    private Paint paint;
    private Path path;
    private float startX;
    private float startY;
    private float endX;
    private float endY;
    private CalcDpi calcDpi;

    public CanvasTest2View(Context context,MainActivity main) {
        super(context);
        path = new Path();
        paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(10);
        calcDpi = new CalcDpi(main);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawPath(path, paint);
        float tatePx = endX - startX;
        float yokoPx = endY - startY;
        double tateCm = Math.sqrt(tatePx*tatePx)/calcDpi.getPxTocm();
        double yokoCm = Math.sqrt(yokoPx*yokoPx)/calcDpi.getPxTocm();

        Log.d("タテ幅", String.valueOf(tateCm));
        Log.d("ヨコ幅", String.valueOf(yokoCm));

    }

    @Override public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
                path.moveTo(x, y);
                invalidate();
                startX = x;
                startY = y;
                endX = x;
                endY = y;
                break;
            case MotionEvent.ACTION_UP:
                path.lineTo(x, y);
                invalidate();
                endX = x;
                endY = y;
                break;
        }
        return true;
    }
}
```

これでタテ幅ヨコ幅をcmで取得することができます。

誰かの参考になれば幸いです。
冒頭で紹介したわたしの曲線定規もgithubとGoogleplayでソースとアプリを公開しておりますので、
ダウンロードしてみていただくと参考になると思います。

Github
https://github.com/kuniatsu/RulerPad

Googleplay
https://play.google.com/store/apps/details?id=com.xample.ux21a.rulerpad