2011年1月28日金曜日

Android開発 - 画面の縦横を検知して回転するボタンを作る(3)

Android開発 - 画面の縦横を検知して回転するボタンを作る(1)
Android開発 - 画面の縦横を検知して回転するボタンを作る(2)

Javaのコードは2種類
・Main.java (メインのアクティビティクラス)
・AnimationController.java (回転アニメーションの制御)
になります。


AnimationController.java

import android.hardware.SensorEvent;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;


public class AnimationController {

boolean yoko = false;
float touchY;
long ANIM_ROTATE_SPEED = 200;

public void rotateCube(SensorEvent event, ImageButton[] img) {


if (!yoko && event.values[2] > 60 && event.values[2] < 80) {

for (ImageButton target: img){
RotateAnimation rotate = new RotateAnimation(0, 90, target.getWidth()/2, target.getHeight()/2);
rotate.setDuration(ANIM_ROTATE_SPEED);
rotate.setFillAfter(true);
target.startAnimation(rotate);
}

yoko = true;
}


if (yoko && event.values[2] > -10 && event.values[2] < 10) {

for (ImageButton target: img){
RotateAnimation rotate = new RotateAnimation(90, 0, target.getWidth()/2, target.getHeight()/2);
rotate.setDuration(ANIM_ROTATE_SPEED);
rotate.setFillAfter(true);
target.startAnimation(rotate);
}

yoko = false;
}
}
}



Main.java



import java.util.List;


import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;


public class Main extends Activity implements SensorEventListener, OnClickListener{

AnimationController animationController = new AnimationController(); 

SensorManager mSensorManager = null;
private boolean mRegisteredSensor;
float touchY;
float moveY;
boolean yoko = false;
RotateAnimation rotateAnimation;


ImageButton button01;
ImageButton button02;
ImageButton button03;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mRegisteredSensor = false;


button01 = (ImageButton)findViewById(R.id.button01);
button02 = (ImageButton)findViewById(R.id.button02);
button03 = (ImageButton)findViewById(R.id.button03);
    }


@Override
protected void onResume() {

List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
if (sensors.size() > 0) {
Sensor sensor = sensors.get(0);
mRegisteredSensor = mSensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST);
}
super.onResume();
}


@Override
protected void onPause() {

if (mRegisteredSensor) {
mSensorManager.unregisterListener(this);
mRegisteredSensor = false;
}
super.onPause();
}


@Override
protected void onStop() {

mSensorManager.unregisterListener(this);
super.onStop();
}


@Override
public void onClick(View v) {


switch( v.getId() ){
case R.id.button01:
//ボタンタッチ時の処理
break;
case R.id.button02:
//ボタンタッチ時の処理
break;
case R.id.button03:
//ボタンタッチ時の処理
break;
}
}


@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}


@Override
public void onSensorChanged(SensorEvent event) {

if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {


ImageButton[] img = {button01,button02,button03};
animationController.rotateCube(event, img);
}
}
}



Main.java の onSensorChanged → Sensor.TYPE_ORIENTATIONで傾きを検知し、SensorEvent と 対象となるボタンを AnimationController に渡しています。

センサーイベントの event.values[2] でY軸の傾きの値が取れます。
event.values[2] = 60〜80 でボタンを横向きに、
event.values[2] = -10〜10 でボタンを縦向きにアニメーションさせていますが、このあたりの設定は改善の余地がありそうです。



センサーイベントの実装は、以下のサイトを参考にさせていただきました。
http://www.adakoda.com/android/000182.html

2011年1月25日火曜日

Android開発 - 画面の縦横を検知して回転するボタンを作る(2)

Android開発 - 画面の縦横を検知して回転するボタンを作る(1)


まずはManifestファイルから

■AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="jp.mediba.android.RotateCube"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" 
                 android:label="@string/app_name"
                 android:debuggable="true" >
        <activity android:name=".Main"
                  android:label="@string/app_name"
                  android:screenOrientation="portrait">
            <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="4" />
</manifest> 



Activityタグ内で android:screenOrientation="portrait" を指定し、画面自体は縦表示で固定します。


続いてレイアウトファイル

■Main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ImageButton
android:id="@+id/button01"
android:src="@drawable/icon"
android:layout_width="wrap_content"
 android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:layout_marginTop="60dp"
></ImageButton>
<ImageButton
android:id="@+id/button02"
android:src="@drawable/icon"
android:layout_width="wrap_content"
 android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:layout_marginTop="60dp"
></ImageButton>
<ImageButton
android:id="@+id/button03"
android:src="@drawable/icon"
android:layout_width="wrap_content"
 android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:layout_marginTop="60dp"
></ImageButton>
</LinearLayout>


サンプルではアプリランチャー的なイメージで ImageButton を使いますが、ImageViewやTextView等でも作成可能です。


次回は実際にアニメーションを行うコードを作っていきます。

Android開発 - 画面の縦横を検知して回転するボタンを作る(3)

Android開発 - 画面の縦横を検知して回転するボタンを作る(1)

Androidアプリの開発で、主にUI関係の話をしていると、
「iPhoneぽく」「iPhoneみたいに・・・」といった要望がしばしば出てきます。

直感的でわかりやすく、且つ格好良いインターフェースという点においてはAndroidよりもiOSに分があるのが現状のようです。


今回は、「画面の縦横切替をアニメーションで多少なりとも格好良く見せる」チャレンジをしてみます。
通常、下のような画面の場合


端末を横向きにすると、



このような画面に切り替わります。

これを
・レイアウトそのものは縦画面で固定
・プログラム内で端末の動きを検知しアイコン画像がアニメーションで90度回転
・アニメーション後は以下のような表示に
してみたいと思います。


続きは次回。

Android開発 - 画面の縦横を検知して回転するボタンを作る(2)

2010年12月10日金曜日

2010年11月29日月曜日

傾き、加速度の手振れノイズをフィルターする

人間の手の震えもありますが、端末で取れる加速度センサーの値は、結構細かく震えています。
この加速度センサーの値をもとにLinearで中心にあるボールを動かしたかったのですが、この震えのせいで、
きれいに移動しないで、ぴょこぴょこと跳ねているような動きに見えてしまうので困りました。

センサーの精度かと思って、そちらを調査してみたり、
アニメーションの処理飛びなのかと思ってログを見てみたりしていたのですが、
特に解決策は見つからず。

結局のところこのブレを減らすための解決策が必要だろうと推測して、ノイズフィルターを探していたところ身近なところに解決策がありました。

DJミキサーでよくある、ハイパスフィルターとローパスフィルターです。

ハイパスフィルターは、つまみを回すとだんだんシャキシャキの音になってくあれですw。
ローパスフィルターは、つまみを回すとだんだんモコモコの音になってくあれですw。


WikiPedia ローパスフィルター(ハイカット)
ローパスフィルタ(Low-pass filter: LPF)はフィルタ回路の一種で、低周波を良く通し、ある遮断周波数より高い周波数の帯域を通さない(減衰させる)フィルタである。

WikiPedia ハイパスフィルター(ローカット)
ハイパスフィルタ(High-pass filter: HPF)はフィルタ回路の一種で、高周波を良く通し、遮断周波数より低い周波数の帯域を通さない(減衰させる)フィルタである。 日本語では「高域通過濾波器」とも言われる。また英語では「low-cut filter」とも言われ、これは「bass-cut filter」または「rumble filter」としてオーディオ機器などで使用される。


加速度は、重力加速度+手振れなどの実際の端末の動きが加速度が影響してきます。
あるXYZで考えてどれか一方向についての変化
重力加速度の変化:端末の大体の傾きになりますので周波数で考えるとだんだん傾いていれば低い周波数です。
端末の動きの変化:手振れなので重力加速度の変化より高い周波数のノイズになります。

ぴょこぴょこと動いてしまうのは、「端末の動きの変化」が影響しているので、高い周波数をカットすればいい。すなわち低い周波数だけ通せばいいということになります。

ってことで、ロジック。
一つ前の値と比較しながら、値を取ります。
XYだけの例です。

部分的に抜き出すとわけわからなくなったので、全部載せます。

イメージを最初に真ん中において、ローパスフィルタをかけた加速度で、イメージを移動しています。

package jp.mediba.android.xxxxxx;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.util.Log;
import android.widget.ImageView;

public class PointViewOverlay extends ImageView {

 private Matrix mMatrix = new Matrix();
 private Matrix mSavedMatrix = new Matrix();
 private float[] currentOrientationValues = {0.0f, 0.0f};
 
 private PointF startPoint = new PointF();
 
 private ImageView imageView;
 private int frameWidth = 0;
 private int frameHeight = 0;
 
 public PointViewOverlay(Context context) {
  super(context);
  // TODO 自動生成されたコンストラクター・スタブ
 }

 public void setImageView(ImageView imageView) {this.imageView = imageView;}
 public void setFrameSize(int frameWidth, int frameHeight) {
  this.frameWidth = frameWidth;
  this.frameHeight = frameHeight;
 }
 
 public void resetStartPoint() {
  mMatrix.set(mSavedMatrix);
  this.startPoint = new PointF((float)this.frameWidth/2,(float)this.frameHeight/2);
  mMatrix.postTranslate(this.startPoint.x, this.startPoint.y);
  imageView.setImageMatrix(mMatrix);
  Log.v("resetStartPoint.",String.valueOf("X:" + this.startPoint.x) + "Y:" + String.valueOf(this.startPoint.y));
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  // TODO 自動生成されたメソッド・スタブ
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 }

 public void animateView( SensorEvent event ) {
  
  if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

   // Lowpass Filter ハイカット これ!
   currentOrientationValues[0] = event.values[0] * 0.1f + currentOrientationValues[0] * (1.0f - 0.1f);
   currentOrientationValues[1] = event.values[1] * 0.1f + currentOrientationValues[1] * (1.0f - 0.1f);

   // 重力加速度
   float accX = currentOrientationValues[0];
   float accY = currentOrientationValues[1];

   // 横画面なのでちょっと大きめにしました。
   float moveX = Math.round(accY*48);
   float moveY = Math.round(accX*32);

   float pointX = this.startPoint.x+moveX;
   float pointY = this.startPoint.y+moveY;
   
   mMatrix.set(mSavedMatrix);
   mMatrix.postTranslate(pointX,pointY);
   
   imageView.setImageMatrix(mMatrix);
   Log.v("animateView","pointX,pointY"+String.valueOf(pointX)+","+String.valueOf(pointY));
   
  }
 }
 
}

2010年11月16日火曜日

DroidDraw Android LayoutXMLのWYSIWYGエディタ

http://www.droiddraw.org/
http://code.google.com/p/droiddraw/

機能を完全には使っていないのですが、レイアウトがWYSIWYGでDrag&Dropできて便利です。
Mac OS X, Windows, Linuxのマルチプラットフォームサポートしています。
使い方さえ覚えればもしかするとデザイナさんでも一人でUI作れるかも?

ADTについているレイアウトエディタだとRelativeLayoutの中に入れた、2つのLinearLayoutを左右にふって上合わせにするプロパティーがどこにあるか見つけにくい(ってかあるのか?)のですが、それをマウス操作で上にあわせたり下にあわせたりできます。
(* (ADT) Android Development Tools for the Eclipse IDE )

これだけで、非常にストレスが減る!
Eclipseと連携して操作する所まで入っていないのですが、ファイルの場所を合わせればリソースファイルも読めるようです。

出力は、.apkパッケージで出力したり、XML単体で出力したりできます。
GUIで要素のIDを付ける操作は、いまいち使い勝手が悪いので、ひと通りの配置まで決めたあとは、XMLをEclipseのADTに貼りつけて、名前を付け直したりしています。

どう書いたらうまく並べられるのかの勉強替わりにもなりますね。
ひと通り慣れたら、プロパティーが覚えられそうなのでHTMLのようにタグがきができるようになれるような気がしています。

一点分かりにくいのが、Layout要素を入れ子にすると、外を囲むレイアウトがなんだったかが、GUI上から見えにくいところかな。

でも何にせよ使う利点は十分にあります。

MoonGiftの紹介記事

2010年11月15日月曜日

XCodeとInterfaceBuilderで10分でモックアプリを作る方法(3)

前回の続き。
全部で5回の予定です。
おそらく5回書き終わってからでないとあまり意味のない記事になっちゃいました…。
でも頑張ります。

では、ボタンを押したら画面遷移する動作を紐付けていきましょう。

まずは、XCodeの左側のツリーから、一番最初の画面の .xib ファイルをダブルクリックして、IB(InterfaceBuilderを立ち上げます。)

立ち上げると、こんな状態です。

1.動作の名前を決める

まず、メインの画面にボタンを押したときの操作を定義します。
先に、それぞれのボタンを押したときの操作を決めておきましょう。

3つボタンがあるので、こんな名前にしてみました。


ヘルプへ = changeViewHelp
設定へ = changeViewSetting
実行へ = changeViewMain

2.「File's Owner」に動作の名前を定義する。
これらを、IBをつかって定義していきます。
これからウィンドウを行ったり来たりするので混乱しないように。www
Document 画面の「File's Owner」をクリックします。



そうすると、右側の「インスペクタ」でこの画面に対するいろいろな設定ができるようになります。が、ここではまだちゃんとは使いません。w
上部にタブが4つ見えると思いますが、( i ) の所を選択してください。
その内容の一番上の「Class」のところに 「NavigationTestViewController」という名前が出ていると思います。これが、この画面の操作の統括をするプログラムの名前です。
(対応して、XCodeの中にも同じ名前のxxx.h xxx.mというファイルがあります。)





それを確認したら、「Class」のボックスにある、矢印をクリックしてください。
そうすると今度は、左側の「Library」のWindowの下側に、 「NavigationTestViewController」というボックスが現れます。


このプルダウンを「Actions」に合わせてください。

その状態で、「+」のボタンが下に現れます。

これをクリックして、3つのボタン操作を定義します。

こんな感じに。



3.「File's Owner」に動作の名前を定義したものを保存する。

これを、実際のファイルに保存します。
下のプルダウンから、「Write Updated Class File」を選択してください。

保護んウィンドウがでるのでこれで、Saveを押します。


もうあるけど、どうする?って聞かれますので「Replace」を押してください。
(置き換えられちゃいます。w まだファイルにはなにもかいていないので、大丈夫。)


4.ボタンの動作を「File's Owner」につなげる。

次に、それぞれのボタンを押した操作を紐付けます。
まずに、「実行へ」のボタンを、Mainの画面機能につなげます。

IBで「実行へ」のボタンをクリックして触ってください。
そうすると、右側の「インスペクタ」でボタンに対するいろいろな設定ができるようになります。




ここで、右側の「Connections」のタブを表示します。
ここには、ボタンの動作がすでに定義されており、押したら、どうとか、おして、指が離れたらどうとか、いろいろつなぐことができます。



ここでは、押して、指が離れたら、画面遷移するということにして、「Touch Up Inside」を使います。
これの右側にある◯をクリックし、ドラッグして、「Document」ウィンドウの「File's Owner」につなげます。「File's Owner」にまで、持って行ってマウスを外します。


と、グレーのサブウィンドウが現れるので、「実行へ」に対応する
changeViewMainをクリックします。



ちゃんとつながると、「Connections」の画面がこんなふうになります。



この状態で、.xibファイルを保存してください。

続いて、XCodeに戻り、画面遷移のプログラムを書きます。
そろそろ時間切れなので、また次…。中途半端でごめんなさい。


10分は無理だなこれ。www 
スゲー速さで作業してYoutubeではや回しビデオでもアップして帳尻合わせやろうかと思ってきました。wwww