iOSでボタンを角丸にする方法

今回はiOSのボタンを角丸にする方法を紹介する。
(実装環境:Xcode 7.3.1)

<設定方法>

1.ButtonをView上に配置する

f:id:MoonMtLab:20170208214229g:plain:w600

2.Buttonの大きさと背景色を変更する

(角丸になったことが分かりやすくするための手順で必須ではない)
f:id:MoonMtLab:20170208214524g:plain:w600

3.ButtonにUser Defined Runtime Attributesを追加する
項目名
Key Path layer.cornerRadius
Type Number
Value 15

Valueに設定する値によって、丸みが調整される。
f:id:MoonMtLab:20170208220623g:plain:w600
残念ながらstoryboard上の見た目は反映されない。

<実行結果>

f:id:MoonMtLab:20170208220705g:plain:w600

Enjoy Programing!!

AdroidのToastを自作する方法

Androidアプリでユーザへの通知によく利用されるものの一つが「Toast」である。
簡潔なコードで記述でき、ユーザの注意を引くことができる。

今回はToastの様なものを自作する方法を紹介する。

元々存在するToastを自作する理由としては、自作する事により自由自在なToastを表示することができるためである。

<方法概要>

1.drawableディレクトリにshapeファイルを作成する
2.layoutディレクトリにviewファイルを作成する
3.自作Toastを表示するためのクラスを作成する

<方法詳細>

1.drawableディレクトリにshapeファイルを作成する

プロジェクトツリーの「res/drawable」で右クリックし、「New」->「Drawable resource file」を選択する。
f:id:MoonMtLab:20161101052722p:plain

表示されたダイアログに対し「File name」に「original_toast_shape」(任意の名前)、「Root element」に「shape」を入力し、「OK」ボタンを押下する。
f:id:MoonMtLab:20161101052753p:plain

drawableディレクトリの配下に「original_toast_shape.xml」ファイルが作成された事を確認する。
f:id:MoonMtLab:20161101052805p:plain

「original_toast_shape.xml」ファイルに下記の定義を加える。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 角丸の定義 -->
    <corners android:radius="15dp" />

    <!-- 背景色の定義 -->
    <solid android:color="#88AFEEEE" />

</shape>
2.layoutディレクトリにviewファイルを作成する

プロジェクトツリーの「res/layout」で右クリックし、「New」->「Layout resource file」を選択する
f:id:MoonMtLab:20161101052823p:plain

表示されたダイアログに対し「File name」に「original_toast_view」(任意の名前)、「Root element」に「RelativeLaout」を入力し、「OK」ボタンを押下する。
f:id:MoonMtLab:20161101052840p:plain

layoutディレクトリの配下に「original_toast_view.xml」ファイルが作成された事を確認する。
f:id:MoonMtLab:20161101052854p:plain

「original_toast_view.xml」ファイルを編集する。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp">

    <TextView
        android:id="@+id/textMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:padding="20dp"
        android:textColor="#edafce"
        android:textSize="20dp"
        android:background="@drawable/original_toast_shape"/>
        <!-- ↑↑↑ original_toast_shapeを適用することで角丸を実現している -->

</RelativeLayout>

[ポイント]
TextViewの「android:background」に手順1で作成したshapeファイル「original_toast_shape」を設定することで、表示される自作Toastを角丸にすることができる。

3.自作Toastを表示するためのクラスを作成する

Androidに元々用意されたいるToastとインターフェイスをなるべく合わせるため、「OriginalToast」クラスを作成する。

「MainActivity」があるパッケージを右クリックし、「New」->「Java Class」を選択する。
f:id:MoonMtLab:20161101052919p:plain

表示されたダイアログに対し、「Name」に「OriginalToast」(任意の名前)、「Kind」に「Class」を入力し、「OK」ボタンを押下する。
f:id:MoonMtLab:20161101052931p:plain

作成された「OriginalToast.java」ファイルを編集する。

package biz.accele.sampleoriginaltoast;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;

public class OriginalToast {

    private static Context _context;
    private static String  _message;
    private static int     _dispTime;

    public static OriginalToast makeText(Context context, String message, int dispTime){

        _context  = context;
        _message  = message;
        _dispTime = dispTime;

        return new OriginalToast();
    }

    public void show(){

        // ルートビューを取得する
        final View rootView = ((Activity)_context).findViewById(android.R.id.content).getRootView();

        // 自作Toast用(手順2で作成)のViewを取得する
        final RelativeLayout layout = (RelativeLayout) (((Activity)_context).getLayoutInflater().inflate(R.layout.original_toast_view, null));

        // 自作Toast用のViewからメッセージを表示するためのTextViewを取得する
        TextView textView =  (TextView)layout.findViewById(R.id.textMessage);

        // 表示するテキストを設定する
        textView.setText(_message);

        // ルートビューに自作Toast用のViewをaddする
        ((ViewGroup)rootView).addView(layout, new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));

        // 自作Toastの削除を予約する
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {

                ((ViewGroup)rootView).removeView(layout);

            }
        }, _dispTime);
    }
}

<使用方法>

下記のコードで自作Toastを表示する事ができる。
Androidに元々用意されているToastに近い記述で、自作Toastを表示できることがわかる。

OriginalToast.makeText(<Context>, <表示する文字列>, <表示する時間(ミリ秒)>).show();

以下にボタンを押下したタイミングで、自作Toastを表示する例を示す。

MainActivity.java

package biz.accele.sampleoriginaltoast;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btn1 = (Button)findViewById(R.id.btn1);
        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                // 手順3で作成した「OriginalToast」クラスを使用して自作Toastを表示する
                // 下記の場合「本日は晴天なり」が3秒間表示される
                OriginalToast.makeText(MainActivity.this, "本日は晴天なり", 3000).show();
            }
        });
    }
}

activity_main.xml

<?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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="biz.accele.sampleoriginaltoast.MainActivity">

    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="自作Toast表示"/>

</RelativeLayout>

<実行結果>

f:id:MoonMtLab:20161101052953p:plain

Enjoy Programing!!

Android StudioのプロジェクトにAARを取り込む方法

一昔前はAndroidアプリで使用するライブラリといえばJAR形式が一般的であったが、最近はAAR形式が用いられる事も多くなってきた。
今回はAAR形式のライブラリをAndroid Studioに取り込む方法を紹介する。

<方法概要>

1.サブプロジェクトとしてaarファイルをプロジェクトに取り込む
2.依存関係を設定する

<方法詳細>

1.サブプロジェクトとしてaarファイルをプロジェクトに取り込む

[File]->[New]->[New Module]を選択し、New Module用のダイアログを表示する。

f:id:MoonMtLab:20161005211459p:plain

表示されたダイアログで「Import .JAR/.AAR Package」を選択して、[Next]ボタンを押下する。

f:id:MoonMtLab:20161005211514p:plain

表示されたダイアログで「File name」に取り込む対象のAARファイルを指定し、「Subproject name」に任意の名前を指定する。
「Subproject name」に指定した名前は、Android Studio上で取り込むライブラリを示す名前になるので、AARライブラリで提供される機能を連想する名前が望ましいと考える。
上記を指定後に[Finish]ボタンを押下する。

f:id:MoonMtLab:20161005211529p:plain

Android Studioのプロジェクトツリー上に「Subproject name」で指定した名前のサブプロジェクトが作成されている事を確認する。

f:id:MoonMtLab:20161005211546p:plain

2.依存関係を設定する

[File]->[Project Structure...]を選択し、Project Structureダイアログを表示する。

f:id:MoonMtLab:20161005211602p:plain

左メニューから、AARライブラリの機能を使用するプロジェクトを選択し、「Dependencies」タブを選択する。

f:id:MoonMtLab:20161005211618p:plain

左下の「+」ボタンを押下し、「Module dependency」を選択する。

f:id:MoonMtLab:20161005211638p:plain

手順1で追加したサブプロジェクトを選択し、「OK」ボタンを押下する。

f:id:MoonMtLab:20161005211654p:plain

「Dependencies」タブの一覧にサブプロジェクトが追加された事を確認し、「OK」ボタンを押下する。

f:id:MoonMtLab:20161005211706p:plain

以上の手順で、AAR形式のライブラリが使用できるようになる。

Enjoy Programing!!

Androidアプリで1次元バーコードを作成する方法3

今回も前回に引き続き、ライブラリを使用せず1次元バーコードを作成・表示する方法を紹介する。
前回はライブラリを使用せず「CODABAR(NW-7)」規格のバーコードを作成・表示したが、今回は「CODE39」規格のバーコードを作成・表示する方法を紹介する。

「CODABAR」規格と「CODE39」規格を比較すると、特徴的なのは使用できる文字種類の数である。
「CODABAR」が基本的に「0〜9」の数字のみ(スタート/ストップキャラクタとして「A〜D」を使用できる)であるのに対し、「CODE39」は「0〜9,A〜Z,-,., (空白),$,/,+,%」の43種類の文字を使用することができる。
ただし、「CODE39」は「CODABAR」と比較して、バーコードの横幅が大きくなってしまうので、桁数の大きなデータをバーコードにした場合、バーコードリーダーの横幅より大きくなってしまい読み取れない事があるので注意が必要である。

「CODE39」と「CODABAR」の作成方法はよく似ているため、前回紹介した「CODABAR」を作成するためのクラスである「MyCodaBarWriter」をほぼ流用することができる。
「CODE39」を作成するためのクラス「MyCode39Writer」のソースコードを以下に示す。

MyCode39Writer.java

package biz.accele.samplebarcode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyCode39Writer {

    //スタートキャラクタ、ストップキャラクタ(*固定)
    private final String START_CHAR = "*";
    private final String END_CHAAR  = "*";

    //バーコードの両端に設けるマージンサイズ(クワイエットゾーン)を棒幅の何個分かで指定する
    private final int SIDE_MARGIN_NUM = 10;

    //エレメントの値
    private final int WHITE = 0;     //白エレメント
    private final int BLACK = 1;     //黒エレメント

    //変換用情報(CODE39の仕様より作成)
    private final int[] convert0  = {BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK};
    private final int[] convert1  = {BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convert2  = {BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convert3  = {BLACK, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK};
    private final int[] convert4  = {BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convert5  = {BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK};
    private final int[] convert6  = {BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK};
    private final int[] convert7  = {BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, BLACK};
    private final int[] convert8  = {BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK};
    private final int[] convert9  = {BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK};
    private final int[] convertA  = {BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convertB  = {BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convertC  = {BLACK, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK};
    private final int[] convertD  = {BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convertE  = {BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK};
    private final int[] convertF  = {BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK};
    private final int[] convertG  = {BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, BLACK};
    private final int[] convertH  = {BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK};
    private final int[] convertI  = {BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK};
    private final int[] convertJ  = {BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK};
    private final int[] convertK  = {BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK};
    private final int[] convertL  = {BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK};
    private final int[] convertM  = {BLACK, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK};
    private final int[] convertN  = {BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK};
    private final int[] convertO  = {BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK};
    private final int[] convertP  = {BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK};
    private final int[] convertQ  = {BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, BLACK};
    private final int[] convertR  = {BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK};
    private final int[] convertS  = {BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK};
    private final int[] convertT  = {BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK};
    private final int[] convertU  = {BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convertV  = {BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convertW  = {BLACK, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK};
    private final int[] convertX  = {BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convertY  = {BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK};
    private final int[] convertZ  = {BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK};
    private final int[] convertHY = {BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, BLACK};   // -
    private final int[] convertPD = {BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK};   // .
    private final int[] convertSP = {BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK};   //  (空白)
    private final int[] convertDL = {BLACK, WHITE, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK};   // $
    private final int[] convertSL = {BLACK, WHITE, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK};   // /
    private final int[] convertPL = {BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, WHITE, BLACK};   // +
    private final int[] convertPC = {BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, WHITE, BLACK};   // %
    private final int[] convertAS = {BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK};   // *

    //変換用情報をMap型に格納する
    private final Map<String, Object> mapConvert = new HashMap<String, Object>(){
        {
            put("0", convert0);
            put("1", convert1);
            put("2", convert2);
            put("3", convert3);
            put("4", convert4);
            put("5", convert5);
            put("6", convert6);
            put("7", convert7);
            put("8", convert8);
            put("9", convert9);
            put("A", convertA);
            put("B", convertB);
            put("C", convertC);
            put("D", convertD);
            put("E", convertE);
            put("F", convertF);
            put("G", convertG);
            put("H", convertH);
            put("I", convertI);
            put("J", convertJ);
            put("K", convertK);
            put("L", convertL);
            put("M", convertM);
            put("N", convertN);
            put("O", convertO);
            put("P", convertP);
            put("Q", convertQ);
            put("R", convertR);
            put("S", convertS);
            put("T", convertT);
            put("U", convertU);
            put("V", convertV);
            put("W", convertW);
            put("X", convertX);
            put("Y", convertY);
            put("Z", convertZ);
            put("-", convertHY);
            put(".", convertPD);
            put(" ", convertSP);
            put("$", convertDL);
            put("/", convertSL);
            put("+", convertPL);
            put("%", convertPC);
            put("*", convertAS);
        }
    };

// ---  以降は前回の「MyCodaBarWriter」クラスと全く同一 -------------------------------------------

    public MyBitMatrix encode(String targetData, int width, int height){

        //スタートキャラクタ、ストップキャラクタの付与
        String exTargetData = START_CHAR + targetData + END_CHAAR;

        //データの変換
        List<Integer> codeArray = convertData(exTargetData);

        //バーコードデータの生成
        MyBitMatrix bitMatrix = createBarcode(codeArray, width, height);

        return bitMatrix;
    }

    // データを変換する
    private List<Integer> convertData(String targetData){

        List<Integer> resultArray = new ArrayList<>();

        //サイドマージン(左)
        for(int i=0; i<SIDE_MARGIN_NUM; i++){
            resultArray.add(WHITE);
        }


        //データ変換
        for(int i=0; i<targetData.length(); i++){

            // 先頭から1文字づつ取り出す
            String targetChar = targetData.substring(i, i+1);

            // 取り出した文字を変換する
            joinArray(resultArray, targetChar);

            // キャラクターギャップ
            resultArray.add(WHITE);
        }

        // 最後のキャラクターギャップを削除する
        resultArray.remove(resultArray.size() - 1);

        //サイドマージン(右)
        for(int i=0; i<SIDE_MARGIN_NUM; i++){
            resultArray.add(WHITE);
        }

        return resultArray;
    }

    //Listの末尾に文字を変換した情報を付け加える
    private void joinArray(List<Integer> resultArray, String targetChar){

        int[] targetArray = (int[])mapConvert.get(targetChar);

        for(int i=0; i<targetArray.length; i++){

            resultArray.add(targetArray[i]);
        }
    }

    //バーコード情報を生成する
    private MyBitMatrix createBarcode(List<Integer> targetData, int width, int height) {

        // バー幅の算出
        int multiple = getBarWidth(targetData.size(), width);

        // バーコード描画サイズの算出
        int drawPx = targetData.size() * multiple;

        // 要求幅に合わせるために必要な調整幅を算出する
        int leftSideAdjust  = (width - drawPx) / 2;

        // 結果を格納するためのBitMatrixをインスタンス化する
        MyBitMatrix output = new MyBitMatrix(width, height);

        // 制御変数の初期化
        int outputX = leftSideAdjust;

        for (int inputX = 0; inputX < targetData.size(); inputX++) {

            if (targetData.get(inputX).intValue() == BLACK) {

                output.setRegion(outputX, 0, multiple, height);
                outputX += multiple;

            }else{

                outputX += multiple;
            }
        }
        return output;
    }

    // 指定されたピクセル数を超えず、かつ最大限大きく描画するためにバー幅の最適値を算出する
    private int getBarWidth(int barCount, int viewWidth){

        int resultMultiple = 1;

        int multiple = 1;

        while(true){

            int px = barCount * multiple;

            if(px > viewWidth){

                break;

            }else{

                resultMultiple = multiple;
            }

            multiple += 1;
        }

        return resultMultiple;
    }
}

「MyCode39Writer」クラスを使用して、バーコードを作成・表示する方法は、前回の内容を参照のこと。

[実行結果]

f:id:MoonMtLab:20160922095943p:plain:w300

Enjoy Programing!!

Androidアプリで1次元バーコードを作成する方法2

前回は「ZXing」ライブラリを使用して、Androidアプリで1次元バーコードを作成・表示する方法を紹介した。
今回はライブラリを使用せず、全て自前で1次元バーコードを作成・表示する方法を紹介する。

今回も1次元バーコード規格は「CODABAR(NW-7)」に限定するものとする。

<前置き>

「ZXing」は優れたバーコード作成・読取り用のライブラリである。
Androidアプリで1次元バーコードを作成・表示する必要があり、「ZXing」が使用できるのであれば、迷わず「ZXing」を使用する事をお勧めする。
今回紹介するライブラリを使用せず、1次元バーコードを表示する方法は、何らかの事情で「ZXing」が使用できない場合の方法と考えて頂きたい。

参考までに筆者が「ZXing」を使用できなかった事情を簡単に紹介する。
・アプリのapkファイルサイズを1KBでも削減する必要があった
・バーコードに一部独自の仕様を実装する必要があった

<ソースコード(ライブラリの代替側)>

「CODABAR(NW-7)」規格の1次元バーコードを作成するために、「ZXing」ライブラリの代替として、「MyCodaBarWriter」と「MyBitMatrix」の2クラスを作成した。

MyCodaBarWriter.java

package biz.accele.samplebarcode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyCodaBarWriter {

    //スタートキャラクタ、ストップキャラクタ(A,B,C,Dの中から選択する)
    private final String START_CHAR = "A";
    private final String END_CHAAR  = "A";

    //バーコードの両端に設けるマージンサイズ(クワイエットゾーン)を棒幅の何個分かで指定する
    private final int SIDE_MARGIN_NUM = 10;

    //エレメントの値
    private final int WHITE = 0;     //白エレメント
    private final int BLACK = 1;     //黒エレメント

    //変換用情報(CODABARの仕様より作成)
    private final int[] convert0 = {BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK};
    private final int[] convert1 = {BLACK, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK};
    private final int[] convert2 = {BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convert3 = {BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK};
    private final int[] convert4 = {BLACK, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK};
    private final int[] convert5 = {BLACK, BLACK, WHITE, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK};
    private final int[] convert6 = {BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convert7 = {BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK, WHITE, BLACK};
    private final int[] convert8 = {BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, BLACK, WHITE, BLACK};
    private final int[] convert9 = {BLACK, BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK};
    private final int[] convertA = {BLACK, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK, WHITE, WHITE, BLACK};
    private final int[] convertB = {BLACK, WHITE, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, BLACK, BLACK};
    private final int[] convertC = {BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK};
    private final int[] convertD = {BLACK, WHITE, BLACK, WHITE, WHITE, BLACK, BLACK, WHITE, WHITE, BLACK};

    //変換用情報をMap型に格納する
    private final Map<String, Object> mapConvert = new HashMap<String, Object>(){
        {
            put("0", convert0);
            put("1", convert1);
            put("2", convert2);
            put("3", convert3);
            put("4", convert4);
            put("5", convert5);
            put("6", convert6);
            put("7", convert7);
            put("8", convert8);
            put("9", convert9);
            put("A", convertA);
            put("B", convertB);
            put("C", convertC);
            put("D", convertD);
        }
    };


    public MyBitMatrix encode(String targetData, int width, int height){

        //スタートキャラクタ、ストップキャラクタの付与
        String exTargetData = START_CHAR + targetData + END_CHAAR;

        //データの変換
        List<Integer> codeArray = convertData(exTargetData);

        //バーコードデータの生成
        MyBitMatrix bitMatrix = createBarcode(codeArray, width, height);

        return bitMatrix;
    }

    // データを変換する
    private List<Integer> convertData(String targetData){

        List<Integer> resultArray = new ArrayList<>();

        //サイドマージン(左)
        for(int i=0; i<SIDE_MARGIN_NUM; i++){
            resultArray.add(WHITE);
        }

        //データ変換
        for(int i=0; i<targetData.length(); i++){

            // 先頭から1文字づつ取り出す
            String targetChar = targetData.substring(i, i+1);

            // 取り出した文字を変換する
            joinArray(resultArray, targetChar);

            // キャラクターギャップ
            resultArray.add(WHITE);
        }

        // 最後のキャラクターギャップを削除する
        resultArray.remove(resultArray.size() - 1);

        //サイドマージン(右)
        for(int i=0; i<SIDE_MARGIN_NUM; i++){
            resultArray.add(WHITE);
        }

        return resultArray;
    }

    //Listの末尾に文字を変換した情報を付け加える
    private void joinArray(List<Integer> resultArray, String targetChar){

        int[] targetArray = (int[])mapConvert.get(targetChar);

        for(int i=0; i<targetArray.length; i++){

            resultArray.add(targetArray[i]);
        }
    }

    //バーコード情報を生成する
    private MyBitMatrix createBarcode(List<Integer> targetData, int width, int height) {

        // バー幅の算出
        int multiple = getBarWidth(targetData.size(), width);

        // バーコード描画サイズの算出
        int drawPx = targetData.size() * multiple;

        // 要求幅に合わせるために必要な調整幅を算出する
        int leftSideAdjust  = (width - drawPx) / 2;

        // 結果を格納するためのBitMatrixをインスタンス化する
        MyBitMatrix output = new MyBitMatrix(width, height);

        // 制御変数の初期化
        int outputX = leftSideAdjust;

        for (int inputX = 0; inputX < targetData.size(); inputX++) {

            if (targetData.get(inputX).intValue() == BLACK) {

                output.setRegion(outputX, 0, multiple, height);
                outputX += multiple;

            }else{

                outputX += multiple;
            }
        }
        return output;
    }

    // 指定されたピクセル数を超えず、かつ最大限大きく描画するためにバー幅の最適値を算出する
    private int getBarWidth(int barCount, int viewWidth){

        int resultMultiple = 1;

        int multiple = 1;

        while(true){

            int px = barCount * multiple;

            if(px > viewWidth){

                break;

            }else{

                resultMultiple = multiple;
            }

            multiple += 1;
        }

        return resultMultiple;
    }
}

MyBitMatrix.java

package biz.accele.samplebarcode;

public final class MyBitMatrix {

    private final int rowSize;
    private final int[] bits;

    public MyBitMatrix(int width, int height) {

        this.rowSize = (width + 31) / 32;
        bits = new int[rowSize * height];
    }

    public boolean get(int x, int y) {
        int offset = y * rowSize + (x / 32);
        return ((bits[offset] >>> (x & 0x1f)) & 1) != 0;
    }

    public void setRegion(int left, int top, int width, int height) {

        int right = left + width;
        int bottom = top + height;

        for (int y = top; y < bottom; y++) {
            int offset = y * rowSize;
            for (int x = left; x < right; x++) {
                bits[offset + (x / 32)] |= 1 << (x & 0x1f);
            }
        }
    }
}

<ソースコード(呼び出し側)>

前回の「ZXing」ライブラリを使用する場合と比較して、変更点は多くない。
(activity_main.xmlに関しては完全に同一である)

MainActivity.java

package biz.accele.samplebarcode;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView imageView = (ImageView) findViewById(R.id.result_view);

        // バーコードの各種設定
        String        targetData = "123456789012345";       //バーコードに変換する対象データ
        int           width      = 1000;                    //作成するバーコードの幅
        int           height     = 200;                     //作成するバーコードの高さ

        // データ変換用クラスをインスタンス化する
        // 変更点1
        // ・CodaBarWriter -> MyCodaBarWriter
        MyCodaBarWriter writer = new MyCodaBarWriter();


        try {

            // 対象データを変換する
            // 変更点2
            // ・BitMatrix -> MyBitMatrix
            // ・引数の数が少なくなった
            MyBitMatrix bitMatrix = writer.encode(targetData, width, height);


            // BitMatrixのデータが「true」の時は「黒」を設定し、「false」の時は「白」を設定する
            int[] pixels = new int[width * height];
            for (int y = 0; y < height; y++) {
                int offset = y * width;
                for (int x = 0; x < width; x++) {
                    pixels[offset + x] = bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE;
                }
            }

            // ビットマップ形式に変換する
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);

            //ビットマップの回転(縦に表示するため)
            Matrix mat = new Matrix();
            mat.postRotate(90);
            Bitmap bmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, mat, true);

            // イメージビューに表示する
            imageView.setImageBitmap(bmp);

        } catch (Exception e) {}
    }
}

activity_main.xml

<?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"
    android:background="#F0E68C"
    tools:context="biz.accele.samplebarcode.MainActivity">

    <!-- バーコードを表示するためのImageView -->
    <ImageView
        android:id="@+id/result_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        />

</RelativeLayout>

<実行結果>

f:id:MoonMtLab:20160918094958p:plain:w300

Enjoy Programing!!

Androidアプリで1次元バーコードを作成する方法1

今回はAndroidアプリで1次元バーコードを作成する方法を紹介する。
バーコードの作成は、Googleが開発した「ZXing」というライブラリを使用する。

1次元バーコードには様々な規格が存在するが、今回は「CODABAR(NW-7)」規格の作成方法を紹介する。

<方法概要>

1.Gradleの設定ファイルにZXingの依存関係を追記する
2.バーコードを表示するためのビューを追加する
3.バーコードを生成するためのソースコードを記述する

<方法詳細>

1.Gradleの設定ファイルにZXingの依存関係を追記する

プロジェクトにバーコードのライブラリであるZXingを取り込むために、build.gradleファイルの「dependencies」に「compile group: 'com.google.zxing', name: 'core', version: '3.2.1'」を追加する。

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"

    defaultConfig {
        applicationId "biz.accele.samplebarcode"
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.2.0'
    compile group: 'com.google.zxing', name: 'core', version: '3.2.1'  //<-追加
}

追加すると画面右上に「Sync Now」のリンクが表示されるので、そのリンクを押下する。

f:id:MoonMtLab:20160917113525p:plain

2.バーコードを表示するためのビューを追加する

生成したバーコードを表示するための「ImageView」を画面レイアウト用のxmlに追加する。

activity_main.xml

<?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"
    android:background="#F0E68C"
    tools:context="biz.accele.samplebarcode.MainActivity">

    <!-- バーコードを表示するためのImageView -->
    <ImageView
        android:id="@+id/result_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        />

</RelativeLayout>
3.バーコードを生成するためのソースコードを記述する

手順1でプロジェクトに取り込んだ「ZXing」ライブラリを使用して、バーコードを生成する。

MainActivity.java

package biz.accele.samplebarcode;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.CodaBarWriter;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView imageView = (ImageView) findViewById(R.id.result_view);

        // バーコードの各種設定
        String targetData = "123456789012345";       //バーコードに変換する対象データ
        int    width      = 1000;                    //作成するバーコードの幅
        int    height     = 200;                     //作成するバーコードの高さ

        // CODABAR規格用のデータ変換クラスをインスタンス化する
        CodaBarWriter writer = new CodaBarWriter();

        try {

            // 対象データを変換する
            BitMatrix bitMatrix = writer.encode(targetData, BarcodeFormat.CODABAR, width, height); //...(1)

            // BitMatrixのデータが「true」の時は「黒」を設定し、「false」の時は「白」を設定する              //...(2)
            int[] pixels = new int[width * height];
            for (int y = 0; y < height; y++) {
                int offset = y * width;
                for (int x = 0; x < width; x++) {
                    pixels[offset + x] = bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE;
                }
            }

            // ビットマップ形式に変換する
            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);

            //ビットマップの回転(縦に表示するため)
            Matrix mat = new Matrix();
            mat.postRotate(90);
            Bitmap bmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, mat, true);

            // イメージビューに表示する
            imageView.setImageBitmap(bmp);

        } catch (WriterException e) {}
    }
}

[解説]
(1)
結果として受け取るBitMatrixは、booleanの2次元配列の様な型であり(厳密には異なるがイメージとして)、1要素が1ピクセルに相当する。

(2)
BitMatrixの情報に従い、要素が「true」の場合は塗りつぶし、要素が「false」の場合は塗りつぶさない処理を行えば、バーコードの描画情報となる。

[実行結果]

f:id:MoonMtLab:20160917113604p:plain:w300

Enjoy Programing!!

Androidにおける遅延実行の実装方法

今回はAndroidにおける遅延実行の実装方法について紹介する。
遅延実行とは、名前から予想できる通り、遅らせて処理を実行することである。

<方法概要>

Handlerクラスの「postDelayed」メソッドを使用して、指定した時間後に、指定した処理を実行する。

postDelayedメソッドの定義は下記の通りである。

postDelayed (Runnable r, long delayMillis)

第1引数に「遅らせて実行したい処理」をRunnable型で指定し、第2引数に「遅らせたい時間」をミリ秒単位で指定する。

<サンプルコード>

以下のサンプルコードは画面上の文字を3秒後に変更するものである。

MainActivity.java

package biz.accele.sampledelay;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    TextView txt1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        txt1 = (TextView)findViewById(R.id.txt1);

        // Handlerクラスをインスタンス化し、postDelayedメソッドを呼んでいる
        new Handler().postDelayed(new Runnable() {
            // Runnable型のインスタンス化と定義
            @Override
            public void run() {

                // 遅らせて実行したい処理
                txt1.setText("本日は晴天なり");
            }
        }, 3000); // 遅らせたい時間(ミリ秒) 3000ミリ秒 -> 3秒
    }
}



activity_main.xml

<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/txt1"
        android:text="@string/hello_world"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

Enjoy Programing!!