2015年3月9日月曜日

Androidで画像を動かす SurfaceViewの使い方

目次へ



  • SurfaceViewとは
  • SurfaceViewを使って画像を動かす例
  • 画像をタッチしたらカウントしてみる


■■■■SurfaceViewとは■■■■

SurfaceViewが他のViewと異なるのはメインスレッド以外のスレッドから描画ができるという点です。
SurfaceView以外では、メインスレッドで描画処理をしなければならないため、定期的に再描画を繰り返すようなものには向きません。 その点、SurfaceViewは別のスレッドを作成し、その中で、ずっと再描画を繰り返すということができます。


■■■■SurfaceViewを使って画像を動かす例■■■■

  • まずは、SurfaceViewを継承したクラスを作成します。下の例のMyViewがそれです。
    コンストラクタでは、あとで表示をする時に使うために、リソースからBitmapオブジェクトを取り出しておきます①。

  • 表示用スレッドをスタートさせるのは画面が表示された時です。②はそのための処理です。
    画面が表示された時に呼び出されるのは、SurfaceHolder.CallbackインターフェースのsurfaceCreatedメソッドです。
    SurfaceHolder.Callbackインターフェースには、surfaceCreated⑤、surfaceChanged⑥、surfaceDestroyed⑦が定義されています。
    これらのメソッドをこのViewに登録するのが②です。

  • DrawThreadクラスは画像を表示するためのスレッドです。
    その中で、表示用のいろいろなメソッドを持つCanvasオブジェクトを取り出しているのが③です。
    このCanvasは他のスレッドからの描画を排他するので、lockCanvasというメソッド名となっています。
    そのため、描画が終わったら他のスレッドからの描画ができるようにするための④が必要です

  • 画像を表示するmydrawメソッドは、canvasを使ってランダムな位置に画像を表示しているだけです。
    このメソッドがスレッドから、2秒おきにずっと呼び出されます


MyViewクラス
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class MyView extends SurfaceView implements Callback {
    Random random = new Random();
    Bitmap bitmap;  //表示画像
    int x;   //表示位置x
    int y;   //表示位置y
    int bitmapWidth; //画像サイズ 幅
    int bitmapHeight; //画像サイズ 高さ

    Thread thread = null; //画像を表示するスレッド

    public MyView(Context context) {
        super(context);
        bitmap = BitmapFactory.decodeResource
                       (getResources(), R.drawable.ic_launcher);     //①
        bitmapWidth = bitmap.getWidth();
        bitmapHeight = bitmap.getHeight();
        getHolder().addCallback(this);                               //②
    }
    //画像を表示するスレッド
    private class DrawThread extends Thread {
        public void run() {
            SurfaceHolder holder = getHolder();
            while(true) {
                Canvas canvas = holder.lockCanvas();                 //③
                if (canvas != null) {
                    mydraw(canvas);
                    holder.unlockCanvasAndPost(canvas);              //④
                }
                try {
                    sleep(2000);
                } catch (InterruptedException e) {}
            }
        }
    }
    //画像を表示する
    private void mydraw(Canvas canvas) {
        canvas.drawColor(Color.WHITE);

        int width  = canvas.getWidth() - bitmapWidth;
        int height = canvas.getHeight() - bitmapHeight;

        x = random.nextInt(width);
        y = random.nextInt(height);

        canvas.drawBitmap(bitmap, x, y, new Paint());
    }
    //-----画面が生成された時に呼び出される            ⑤
    public void surfaceCreated(SurfaceHolder holder) {
        thread = new DrawThread();
        thread.start();
    }
    //-----画面のサイズ等が変化した時に呼び出される    ⑥
    public void surfaceChanged(SurfaceHolder holder,
                            int format, int width, int height) {
    }
    //-----画面が削除された時に呼び出される            ⑦
    public void surfaceDestroyed(SurfaceHolder holder) {
       thread = null;
    }
}



このMyViewクラスのインスタンスをActivityクラスのonCreate内のsetContentViewに渡せば表示されます。


Activityクラス
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(new MyView(this));
 }



■■■■画像をタッチしたらカウントしてみる■■■■

上のMyViewクラスのフィールドに、画像をタッチできたらカウントしてその数を表示するようにしてみます。


public class MyView extends SurfaceView implements Callback {
    ------フィールド追加------
    int count = 0; 

    private void mydraw(Canvas canvas) {
        ------最後に次の3行を追加------
        Paint p = new Paint();
        p.setTextSize(35);
        canvas.drawText("タッチできた数"+count, 50, 50, p);
    }

    -------タッチした時に呼び出されるメソッドを追加------
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int cx = (int)event.getX();
        int cy = (int)event.getY();
        if(x <= cx && cx <= x+bitmapWidth && y < cy && cy <= y+bitmapHeight) {
            count++;
        }
        return super.onTouchEvent(event);
    }
}



にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2015年1月27日火曜日

Googleマイマップ をブログに埋め込む

目次へ



Google のマイマップを作成し、地図上にラインなどを描画したものをWebサイトやブログに貼りつける方法です。


■■■■マイマップを作成■■■■

Googleアカウントでログインし、Google Mapの検索ボックスをクリックするとマイマップ作成リンクがあるのでそれをクリック。
その後、作成リンクをクリックします。




この後、下のようなボタンが表示され、マーカを作成、ライン描画、ルート表示、などができるようになります。




できあがったら、無題の地図と表示されているところをクリックし、タイトルなどを入力し、保存ボタンを押せばマイマップが作成できます。


■■■■マイマップを表示■■■■

Google Mapの検索ボックスをクリック、マイマップをクリック、 表示されるマイマップのタイトルをクリックで、保存したマイマップを表示することができます。


■■■■マイマップを埋め込む■■■■

まず、一般公開の設定です。
共有(赤い矢印)をクリックしし、共有設定のウィンドウで、非公開と表示されている部分の右にある、「変更」をクリックします。
新しく表示されたリンクの共有ウィンドウで、「ウェブ上で一般公開」を選択し、保存をします。
これで、一般公開ができるようになりました。

次は、マイマップを埋め込むためのコードを取得します。
下の図の黒い矢印の部分をクリックします。すると、メニューが出てきますので、その中の、「自分のウェブサイトに埋め込む」をクリックします。
すると、「<iframe src=・・・」と書かれたHTMLが表示されますので、それをコピーして、自分のブログなどに貼り付ければOKです。





■■■■マイマップを削除■■■■

上の図の黒い矢印をクリックしたときに出てくるメニューの中に、「この地図を削除する」があるので、それをクリックすれば、その時表示されているマイマップを削除することができます。





にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2015年1月11日日曜日

Conversion to Dalvik format failed の対処

目次へ



EclipseでAndroidプロジェクトを作成している時にコンパイルエラーが表示されているわけでもないのに実行してみると「Conversion to Dalvik format failed」と表示され実行できない時の対処です。


■■■■対処法■■■■

Android プロジェクトを実行をしてみると Conversion to Dalvik format failed のエラーが出ました。 コンパイルエラーが表示されていないのでわけが分からず検索をしてみました。 http://ksggk.hateblo.jp/entry/2013/12/08/213316 のページを参考にさせていただきました。 自分の場合1から順番に試してみたところ、eclipseのクリーンを実行したところで、うまくいきましたので、4,5は試していません。
  1. プロジェクト→クリーン
    プロジェクトをクリックし、メニューの[プロジェクト]-[クリーン]をクリック
  2. プロジェクトを右クリックし[Androidツール]-[プロジェクト・プロパティーを修正]
  3. eclipseのクリーン
    eclipseフォルダ内のeclipse.exe -clean.cmd(eclipse.exe -cleanを実行と同じ)を使ってeclipseを再起動
  4. binとgenフォルダの削除
    これ
  5. プロジェクトのビルド・パスの構成→順序およびエクスポートの調整



ところで、eclipseの-cleanオプションははどのような時に使うかというと、プラグインを追加した直後の起動では、このオプションの指定が必須だそうです。
また、毎回付加しても問題のないオプションです。ただちょっと起動が遅くなります。


にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2014年7月8日火曜日

Androidアプリのパッケージ名を変更する方法

目次へ



プロジェクト作成時にcom.example.xxという名前のパッケージ名をつけておくと、禁止された名前のため、このアプリを公開できません。
そこで、すでに作成してしまったパッケージ名を変更する方法を書いておきます(ECLIPSEでの方法)
  1. srcフォルダ内のパッケージ名変更
  2. AndroidManifest.xmlを変更する
の2つです。


■■■■src内のパッケージ名変更■■■■

ECLIPSEのパッケージエクスプローラで、プロジェクトのsrcフォルダの中のパッケージ名を右クリックし、 [リファクタリング]-[名前変更]を順にクリックし、com.example.xx以外の名前を決めます。
これでsrc内のパッケージ名は変更できます。

■■■■AndroidManifest.xmlの変更■■■■

次はgenフォルダの中のパッケージ名を変更します。
これは、AndroidManifest.xml内で指定することにより、変更できます。
manifestタグの中のpackage=の値を上で変更したsrcのパッケージ名と同じものにして保存します


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.xx"  ←この名前を変更する
    android:versionCode="1"
    android:versionName="1.0" >


この2つの操作でsrcとgenの中のパッケージ名が変更できます。
genの中には、もう一つ、android.support.xxxというパッケージがありますがそれはそのままでOKです。



これでapkファイルを作成し、アプリを公開すれば、パッケージ名でおこられることはありません。
アプリ公開の方法はこちら(Androidアプリを公開する)です。


にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2014年7月5日土曜日

AndroidのLayout  RelativeLayout

目次へ



RelativeLayoutでは、その中に置く部品をParentあるいは、他の部品との位置でしめすことにより、レイアウトします。


■■■■ RelativeLayoutの例 ■■■■



次のような画面は下のようなレイアウトファイルを使いました。


レイアウトファイル

<RelativeLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:text="ボタン1" />
    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/button1"
        android:text="ボタン2" />
    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="ボタン3" />
    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="ボタン4" />
    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/button1"
        android:layout_alignParentTop="true"
        android:text="ボタン5" />
    <Button
        android:id="@+id/button6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/button2"
        android:layout_below="@id/button2"
        android:text="ボタン6" />

</RelativeLayout>




Relative Layoutの属性まとめ
親コンテナを基準にする方法と、他の部品を基準にする方法があります。
属性意味
layout_alignParentTop true 親コンテナの上端に配置
layout_alignParentBottom true 親コンテナの下端に配置
layout_alignParentLeft true 親コンテナの左端に配置
layout_alignParentRight true 親コンテナの右端に配置
layout_centerHorizontal true 親コンテナの水平方向の中央に配置
layout_centerVertical true 親コンテナの垂直方向の中央に配置
layout_centerParent true 親コンテナの水平垂直の中心に配置
layout_below "@id/button1" button1というIDのコンポーネントの下に配置
layout_above "@id/button1" button1というIDのコンポーネントの上に配置
layout_toLeftOf "@id/button1" button1というIDのコンポーネントの左に配置
layout_toRightOf "@id/button1" button1というIDのコンポーネントの右に配置



にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2014年6月5日木曜日

AndroidのEditTextを使う

目次へ



Androidで文字を入力してもらうには、EditTextを使います。
  • EditTextのプロパティ(hint、inputType)
  • 入力された文字列の取り出し


■■■■いろいろなプロパティ■■■■

EditTextでは、入力文字列をチェックして、たとえば、数字しか入力できないようなEditTextを作ることができます。
そんな時に使うのがinputTypeというものです。

また、EditTextに何も入力されていない時に、表示しておく文字列をヒントといいます。
ヒントとして使う文字列はres/values/strings.xmlに登録しておきます。



文字列をリソースとして登録
<string name="prompt">ここに〇〇を入力</string>


リソースのレイアウトres/layout/activity_main.xmlでinputType、hintを設定する。
<EditText
     android:id="@+id/edit1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:inputType="textMultiLine"
     android:hint="@string/prompt"  />


android:inputTypeについて

android:inputTypeを指定するとたとえば、数字しか入力できないなどを指定することができます。
リソースで登録しておく場合とプログラムで指定する場合があると思いますが、 プログラムで指定するには、setInputTypeメソッドを使います。
EditText edit = (EditText)findViewById(R.id.edit1);
edit.setInputType
    (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL);


よく使いそうな、入力チェックについて、リソースで指定する場合の値とプログラムで指定する場合の引数を次にまとめてみました。
入力値 android:inputTypeで指定するもの EditText#setInputTypeメソッドの引数
改行なしテキスト text InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL
改行含むテキスト textMultiLine InputType. TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE
パスワード入力 textPassword InputType. TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
符号なし整数 number InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL
符号付き整数 numberSigned InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED
小数点含めた数字 numberDecimal InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL


android:hintについて

android:hintでの指定をプログラムで行うにはsetHintメソッドを使います。
EditText edit = (EditText)findViewById(R.id.edit1);
edit.setHint(R.string.prompt);



■■■■入力された値を取り出す■■■■

プログラムで入力されたテキストを取得するには、次のように、getText().toString()で取得します。

EditText edit = (EditText)findViewById(R.id.edit1);
String str = edit.getText().toString();



にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2014年5月29日木曜日

AndroidのSpinnerを使う

目次へ



次の3点について、書きます。
  • Spinnerの表示項目をリソースファイルだけで設定する方法
  • 表示項目をプログラムで動的に作成する方法
  • 選択された時のリスナ


■■■■リソースだけで表示項目を設定する方法■■■■

まずプロンプト(項目の上に表示する文字列)と選択項目とをres/values/strings.xmlにstringとstring-arrayとして登録しておきます。
ただ、なぜか、プロンプトがどうしても表示されませんでした。
その理由がわかったら、ここに追加します。


<string name="prompt">項目を選択してください</string>
<string-array name="kinds">
    <item >項目1</item>
    <item >項目2</item>
    <item >項目3</item>
</string-array>



次にres/layout/activity_main.xmlにSpinnerを登録します。


<Spinner
    android:id="@+id/spinner1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:entries="@array/kinds"    ← string-arrayのname
    android:prompt="@string/prompt" /> ← stringのname



■■■■表示項目をプログラムで動的に作成し、項目が選択された時Toast表示■■■■

リソースのレイアウト(res/layout/activity_main.xml)ではentriesとpromptはなしでSpinnerを登録します。


<Spinner
    android:id="@+id/spinner1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />


ActivityのonCreateでは、
  • ArrayAdapterを使って選択項目を登録し、
  • プロンプトを登録し、
  • 項目が選択されたらそれを表示します


protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 strs = getResources().getStringArray(R.array.kinds);

 //--------------------------スピナー取り出し
 spinner = (Spinner)findViewById(R.id.spinner1);

 //--------------------------スピナー用アダプタ
 ArrayAdapter adapter = new ArrayAdapter
   (this,android.R.layout.simple_spinner_item, strs);
 spinner.setAdapter(adapter);


 //-------------------------- Spinnerのレイアウトとプロンプト
 adapter.setDropDownViewResource
          (android.R.layout.simple_spinner_dropdown_item);
 spinner.setPromptId(R.string.prompt);

 //-------------------------- Spinnerが選択された時の処理
 spinner.setOnItemSelectedListener(new OnItemSelectedListener(){
  public void onItemSelected(AdapterView parent, 
                View view, int position, long id) {
   String item = (String) spinner.getSelectedItem();
   Toast.makeText(MainActivity.this, 
                                      item, Toast.LENGTH_LONG).show();
  }
  public void onNothingSelected(AdapterView parent) {
  }
 });
}



にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村