woshidan's blog

あいとゆうきとITと、とっておきの話。

自作のViewを作成してxmlファイルでレイアウトできるようにする

Androidでピアノ弾く感じのアプリが作りたくて、とりあえず

Buttonを並べて、それぞれのButtonをクリックしたらSoundPool使って音を鳴らすところまで作ってみました。

 

ですが、これだといかんせん、ボタンをはじいたときに音が鳴るため、

ピアノを弾いているというより、弦を弾いているような感じがあります。

 

そのため、改良案として

  • ボタンをタッチした瞬間に音がなるようにする
  • 画面をタッチした(&指を離した)ときの位置を取得→位置からどの音が鳴るか判定&鍵盤っぽい背景用意

を考えました。

 

で、最初は下の方で考えていたのですが、

  • 座標ってAndroidの画面の大きさによって変わる->その判定が必要?
  • イベントを起こす前に毎回座標についての判定を行う?
  • せっかくだから複数タッチしたい。その場合配列で値が渡される感じなのだけどその配列の長さ分判定処理書くの? ループの中にループ入って……?

などなど考えていたら、

普通に書いただけで二個くらい押しても動くしやっぱりボタン使いたいな!ってなりまして、ボタンで押した瞬間に動かせないか試したんだけど難しかったので、

ボタンっぽいViewを自作してしまおう!という流れになりました。

あれこれ試したり逃避してたら一日つぶれて下の案の方が早かったんじゃないか?

となったのですが、とりあえず自作のViewをxmlで並べられるところまで来たのでまとめます……。

 

では、本題。

自作のViewを作成してxmlファイルでレイアウトできるようにするためには?

  1. 自作のViewのクラスを書くJavaファイルを他のActivityのJavaファイルがあるフォルダに作成
  2. Viewクラスを継承して自作ビュー用のクラスを作成
  3. まず、ContextとAttributeSetを引数に取る自作ビュークラスのコンストラクタを作成
  4. 次に、自作ビュークラスのonDrawメソッドをオーバーライドする
  5. 自作ビュークラスのonMeasureメソッドで自作ビューの大きさを指定
  6. 5までで作成した自作ビューをxmlファイルに追加

聞きなれない変数とかあって非常に苦戦したので、以下引っかかった部分について説明をつけていきます。

必要なパッケージは電球マークが出次第インポートする形です。

 

1.自作のViewのクラスを書くJavaファイルを他のActivityのJavaファイルがあるフォルダに作成

プロジェクトを作成したときにMainActivity.javaなど最初のアクティビティファイルが作られるフォルダに(自作ビュー名).javaを作成します。

2.Viewクラスを継承してクラスを作成

1.で作ったjavaファイルの中にViewクラスを継承して、自作ビューのクラスを作成します。後で例として出すコードでは自作Viewのクラス名はCustomButtonにします。

3.自作ビュークラスの中にContextとAttributeSetを引数に取るコンストラクタを作成

2.で作ったクラスのコンストラクタを作成する必要があります。

候補が

  • public View(Context context)
  • public View(Context context, AttributeSet attrs)
  • public View(Context context, AttributeSet attrs, int defStyle)

(http://techbooster.jpn.org/andriod/application/3013/ から引用)

の3つ表示されると思うのですが、xmlファイルに自作ビューを追加したときに読み込まれるのは、ContextとAttributeSetを引数に持つもので、今回は真ん中のものを使用します。

コンストラクタの中身はsuper(コンストラクタの引数)でOKです。

Contextは自作ビューをどこに描くか、という情報を追加しているような気がします。

Contextだけを持つものしか作成されていないとxmlファイルに追加したとき、問題が発生したので終了しますと表示されて強制終了するみたいです。

AttributeSetというのは何かよく分からなかったのですが、xmlの方で自作ビューの要素に対して設定したlayout_widthなどのパラメータの値のことをさしているようです。

自分で二時間くらいどこの値だとうんうん悩んでましたが、ここの記事が分かりやすくまとまっています。

http://fujiiyuuki.blogspot.jp/2012/02/android-viewstyle.html

↑三つ目にあるdefStyleについても説明があります。

 

4.自作ビュークラスのonDrawメソッドをオーバーライドする

Android Developerによれば、自作ビューを動かすのに必要最低限なメソッドはonDrawとコンストラクタだけらしいです。ビューを作成したら自動的に実行されます。コンストラクタの中にメソッドの実行を書く必要はありません。

さて、onDrawメソッドが何をするメソッドかといいますと、Viewの見た目を描写するメソッドです。onDrawメソッドを作っておけば、中身を書かなくても一応xmlファイルに追加したりは出来ますが描写してない=透明なので、成功したかよく分かりません。

自分はcanvas.drawColor()でViewの背景色を指定しておきました。

5.onMeasureメソッドで自作ビューの大きさを指定

4まで書けば一応自作ビューを使えますが、4までにサイズの指定が入っていないため、ビューは背景いっぱいに広がっている形で作成されることとなります。

そのままだと大体の場合困るので、onMeasureメソッドで大きさを指定します。また、onMeasureメソッドについては少しややこしいのですが、よく分からなくて困ったら、とりあえずonMeasureメソッドの中にsetMeasuredDimension(横幅,縦幅)って具体的に書いてみて大きさを手動で指定すればいいんではないでしょうか。

一番最後に実際のコードをのせておきますが、それのとおりに書くと、xmlで指定した幅によってビューのサイズが変更されるようになります。

MainActivity.javaでレイアウトを作成してその中に埋め込む形でxmlを通さない場合は、画面の横幅・縦幅いっぱいになったかと。

 

6.5までで作成した自作ビューをxmlファイルに追加

Buttonなどあらかじめgoogleから用意されているビューとちがって、自作ビューの場合は、ビューのクラス名の変わりに、"パッケージ名.クラス名"という形のURIでしっかり書く必要があります。

(これがどう書けばいいかでまた一時間くらいぼけーっとしていたのですがorz)

パッケージ名は自作ビューを作成するときインポートすることになるパッケージ名で、以下で上げるコートだと、package com.woshidan.test140208のcom.woshidan.test140208の部分にあたります。

 

以上を実際に書いてみたコードが以下になります。

多少余分な部分はありますが……。

 

CustomButton.java(自作ビューのクラスを書いたjava)

 
package com.woshidan.test140208;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;


public class CustomButton extends View {
	//ActivityからContext(この場合描写先、ということ?)だけを指定してインスタンスを作成したときに呼び出される
	//コンストラクタ
	public CustomButton(Context cont) {
		super(cont);
	}
	//xmlファイルにuri+クラス名でタグを作って、アクティビティに追加するときに呼び出されるコンストラクタ
	//AttributeSetというのはタグ内にあるlayout_width=""などらしい
	public CustomButton(Context cont, AttributeSet attr) {
		super(cont,attr);
	}
	
	@Override
	protected void onDraw(Canvas canvas){
		canvas.drawColor(Color.BLACK);
	}
	
	//xmlでlayout_width,layout_heightを指定すると指定したサイズに応じた大きさになります
	//(ただしspでなくて画素とかのような気がする……?)
	//コンストラクタだけでActivityから呼び出した(=AttributeSetなしで呼び出した)ときは、widthMeasureSpecなどは画面の縦幅、横幅になるみたいです。
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);
	    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
	    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
	    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
		setMeasuredDimension(widthSize,heightSize);
	}
	
	
}

MainActibity.xmlの自作ビューを置く部分

 

<com.woshidan.test140208.CustomButton
        android:layout_width="40sp"
        android:layout_height="100sp"
        android:layout_marginLeft="10sp"
        />

 

とりあえずこれで自分で作ったビューをxmlファイルに書き込む形で配置することができます。

割とレイアウトのインスタンスをonCreateの中で作成して、それの要素を追加する形で自作ビューを入れるものは多いんですが、xmlに書いていく形の説明が少なくて難儀しました。。

後はタッチ時イベントなどをCustomButton.javaに書き足していけばいいのかな、と思います。

 

 

最後になりましたが、参考にしたのは、

Android DevelopersのViewのページ

http://developer.android.com/reference/android/view/View.html

Tech Booster Viewをカスタマイズ(独自実装)する

http://techbooster.org/android/application/3013/

Code Snipets Android:自作ViewをXMLタグにする

http://miffysora.wikidot.com/ja:customview

GE Android Blog 自作Viewのサイズを自動調整する

http://blog.global-eng.co.jp/android/2011/04/22/%E8%87%AA%E4%BD%9Cview%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E8%87%AA%E5%8B%95%E8%AA%BF%E6%95%B4%E3%81%99%E3%82%8B/

Allabout [android]グラフィックを描こう!

http://allabout.co.jp/gm/gc/80740/

BLOG 備忘録 Android, Viewにstyleを動的に設定する方法

http://fujiiyuuki.blogspot.jp/2012/02/android-viewstyle.html

あと、直接関係ないですがビューの配置について

TechBooster Viewを任意の位置に配置する

http://techbooster.jpn.org/andriod/application/8000/

 

そろそろ大学のレポートもやらないと……。