【Android】動画を再生する
Androidで動画を再生するためには、いくつか方法があるみたいですが、
基本的な方法であるMediaPlayer
とVideoView
を使った再生方法を試してみました。
MediaPlayerを使って再生する
MediaPlayer
で動画を再生する為には、SurfaceView
を使用します。
SurfaceView
は、グラフィックを描画する為のViewで
SurfaceHolder.Callback
というInterfaceを使用してViewの管理を行います。
リファレンス
http://developer.android.com/reference/android/media/MediaPlayer.html
レイアウトの準備
<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" > <SurfaceView android:id="@+id/surfaceView" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
実装ソース
public class MainActivity extends Activity implements SurfaceHolder.Callback { SurfaceView mSurfaceView; SurfaceHolder mSurfaceHolder; MediaPlayer mMediaPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Windowを透明にする getWindow().setFormat(PixelFormat.TRANSPARENT); mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView); // SurfaceHolderを取得する mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); } @Override protected void onDestroy() { // メディアプレーヤーを解放する if (mMediaPlayer != null) { mMediaPlayer.release(); mMediaPlayer = null; } super.onDestroy(); }; @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void surfaceCreated(SurfaceHolder holder) { String path = Environment.getExternalStorageDirectory().toString() + "/video.mp4"; mMediaPlayer = new MediaPlayer(); try { mMediaPlayer.setDataSource(path); // 画面にSurfaceHolderを指定する mMediaPlayer.setDisplay(holder); mMediaPlayer.prepare(); mMediaPlayer.setOnPreparedListener(new MediaPlayer. OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mMediaPlayer.start(); } }); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { // メディアプレーヤーを解放する if(mMediaPlayer != null){ mMediaPlayer.release(); mMediaPlayer = null; } } }
VideoViewで再生する
VideoView
は、内部でMediaPlayer
を使用したウィジェットで
MediaPlayer
よりも簡易に動画の再生が可能です。
リファレンス
http://developer.android.com/reference/android/widget/VideoView.html
レイアウトの準備
<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" > <VideoView android:id="@+id/videoView" android:layout_height="wrap_content" android:layout_width="wrap_content" /> </RelativeLayout>
ファイルPathから再生
VideoView view = (VideoView) findViewById(R.id.videoView); videoView.setVideoPath(Environment.getExternalStorageDirectory().toString() + "/video.mp4"); videoView.start();
URLから再生
VideoView view = (VideoView) findViewById(R.id.videoView); videoView.setVideoURI(Uri.parse("http://sample/sample.mp4")); videoView.start();
再生コントローラを使用する
OSが準備する再生コントローラを使用するには、MediaController
クラスを使用します。
videoView.setMediaController(new MediaController(this));
注意点
上記サンプルソースでは、setVideoPath()
または、setVideoURI()
直後にstart()を実行していますが、
setVideoXX
メソッドは、非同期であるため準備ができるまで再生を待つ必要があります。
そのため、リスナーを設定し、準備が完了してから再生を行うのが正しい実装です。
VideoView view = (VideoView) findViewById(R.id.videoView); videoView.setVideoPath(Environment.getExternalStorageDirectory().toString() + "/video.mp4"); videoView.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { videoView.start(); } });
再生フォーマット
VideoView
およびMediaPlayer
の再生フォーマットは下記を参照して下さい。
http://developer.android.com/guide/appendix/media-formats.html
【iOS】画面遷移にUIKit Dynamicsのアニメーションを使ってみる
iOS7から使えるようになったカスタムの画面遷移UIViewControllerTransitioningDelegate
と
同じくiOS7から使えるようになった物理エンジンのラッパーUIKit Dynamics
を
組み合わせて画面遷移アニメーションを作ってみたいと思います。
今回は、重力によって地面に落ちて画面遷移するアニメーションを作成します。
落ちるときは、画面下に衝突した時に跳ねるようにしています。
また、表示するときは、天井にぶつかって跳ねる用にしました。
UIKit Dynamicsの準備
まずViewControllerの画面遷移で使用するUIViewControllerAnimatedTransitioning
に準拠したクラスを作成します。
今回は、UIKit Dynamics
を使ってアニメーションを行いたいので、UIDynamicBehavior
クラスを継承して作成します。
■ DropTransition.h
@interface INNDropViewBehavior : UIDynamicBehavior <UIViewControllerAnimatedTransitioning> @end
■ DropTransition.m
// class extension @interface DropTransition () <UIViewControllerAnimatedTransitioning, UIDynamicAnimatorDelegate> @property (nonatomic, strong) UIDynamicAnimator *animator; @property (nonatomic, strong) id <UIViewControllerContextTransitioning> transitionContext; @end @implementation DropTransition #pragma mark UIViewControllerAnimatedTransitioning - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { self.transitionContext = transitionContext; UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView *containerView = [transitionContext containerView]; // アニメーション対象のView(=遷移先のView) UIView *frontView = nil; UIView *backView = nil; CGVector gravityDirection; if (self.isPresent) { // 表示 frontView = toVC.view; backView = fromVC.view; // 画面の表示と非表示で重力の方向を逆にする gravityDirection = CGVectorMake(0, -1.0); frontView.frame = CGRectOffset(frontView.frame, 0, frontView.bounds.size.height); } else { // 画面閉じる frontView = fromVC.view; backView = toVC.view; gravityDirection = CGVectorMake(0, 1.0); } /* Viewの準備 */ [containerView addSubview:backView]; // アニメーションを行うViewは、跳ね返りをするために縦方向に2倍の高さを取る CGRect frame = [transitionContext initialFrameForViewController:fromVC]; UIView *canvasView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height * 2)]; [canvasView addSubview:frontView]; [containerView addSubview:canvasView]; /* UIKitDynamicsの準備 */ self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:canvasView]; self.animator.delegate = self; // 重力 UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[frontView]]; [self addChildBehavior:gravityBehavior]; gravityBehavior.gravityDirection = gravityDirection; // 衝突 UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[frontView]]; collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:collisionBehavior]; // property UIDynamicItemBehavior *propertyBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[frontView]]; propertyBehavior.elasticity = 0.4; // 弾力 propertyBehavior.friction = 1.0; // 摩擦 [self addChildBehavior:propertyBehavior]; [self.animator addBehavior:self]; } // TODO: 物理計算のアニメーションなので、秒数が正確にとれない.. - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext { return 0; } #pragma mark - UIViewControllerAnimatedTransitioning - (void)animationEnded:(BOOL)transitionCompleted { // contextの解放 [self.animator.referenceView removeFromSuperview]; self.animator = nil; self.transitionContext = nil; } #pragma mark - #pragma mark UIDynamicAnimatorDelegate - (void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator { // アニメーションが終わった時点で通知する [self.transitionContext completeTransition:YES]; } @end
ViewControllerの準備
次に、画面遷移元となるViewControllerにUIViewControllerTransitioningDelegate
のデリゲートメソッドを準備します。
■ ViewController.m
// 遷移は、segueを使用 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"moveto"]) { // 遷移先のViewControllerのtransitionを独自で行うようにdelegateを指定する [segue.destinationViewController setTransitioningDelegate:self]; } } #pragma mark - UIViewControllerAnimatedTransitioning -(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed { DropTransition *transition = [[DropTransition alloc] init]; transition = NO; return behavior; } - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { DropTransition *behavior = [[DropTransition alloc] init]; behavior.isPresent = YES; return transition; }
これだけで、モーダルの遷移を独自に実装できます。
面白いアニメーションも簡単に実装できそうなので色々試してみたいです。
※
画面の用途によってアニメーションを切り分けたい場合は、UIViewControllerAnimatedTransitioning
は遷移先のViewControllerに設定するでもいいかもしれません。
【Android】Styleの使い方
スタイルとはなに?
レイアウト属性とその値のセットをいくつか組み合わせて, 1つのIDで使用できるように定義したもです。
何のために使用する?
複数のレイアウト属性を共通で使いまわすために使用します。
例えばテキストの”フォント”、”フォントサイズ”、”フォントカラー”などの スタイルのセットを共通で使いまわすことができます。
どうやって使う?
res/values/の配下にxmlファイルを配置します。
idをソース上で使用する場合は、(R.style.*)として参照します。
<?xml version="1.0" encoding="utf-8"?> <resources> <style name=“[id名]”> <item name="android:textStyle">italic</item> <item name="android:textColor">#ffffff</item> </style> <style name="[id名]" parent="@style/FontAttr"> <item name="android:textSize">16sp</item> </style> </resources>
layout.xml上で定義する場合は、
style
属性に@style/[id名]
で参照できます。
<TextView style="@style/[id名]” android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="style text" />
どんなもの(スタイル)が定義できる?
<item>
に定義できる属性は、classリファレンスにサポートしているXML属性が記載されています。
親のスタイルを継承した場合
定義したスタイルを継承して新たなスタイルを作成することが可能です。
その場合は、<style>
タグにparent
属性を定義します。
例:
<style name=“[id名]” parent="@style/[親のid]”> <item name="android:textSize">16sp</item> </style>
【Android】selecterを使ってみる
selecterとは
Androidのdrawable
リソースの一つで、
状態によって、画像や色を差し替えることができる仕組みです。
(StateListDrawable
に分類される)
どうやって定義する?
xmlで作成します。
ファイルの置き場所は、res/drawable
配下になります。
selecterで表現できるの主な状態には、下記5パターンが存在します。
1.フォーカス時
2.無効状態かつフォーカス時
3.押下状態
4.無効状態
5.通常状態
(ファイル例)
<?xml version="1.0" encoding="UTF-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- フォーカス時 --> <item android:state_focused="true" android:state_enabled="true" android:state_pressed="false" android:drawable="@drawable/focused" /> <!-- 無効状態 かつ フォーカス時 --> <item android:state_focused="true" android:state_enabled="false" android:state_pressed="false" android:drawable="@drawable/disabled_and_focused" /> <!-- 押下状態 --> <item android:state_focused="true" android:state_enabled="true" android:state_pressed="true" android:drawable="@drawable/pressed" /> <!-- 無効状態 --> <item android:state_enabled="false" android:drawable="@drawable/disabled" /> <!-- 通常状態 --> <item android:drawable="@drawable/normal" /> </selector>
selecterのxmlで指定する<Item>
タグは、上から評価されるため。
上記すべての状態において別のdrawableを指定したい場合は、
順番どおり記述する必要があります。
どうやって使用する?
レイアウトxmlで指定します。
(ImageViewの画像を状態ごとに変更したいとき)
<ImageView android:layout_height="wrap_content" android:layout_width="wrap_content" android:src="@drawable/sample_selecter” />
(TextViewの文字色を選択状態ごとに変更したいとき)
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" android:textColor="@drawable/sample_selecter"/>
@drawable/[selecterのファイル名]
で指定することができます。
その他ハマりどころ
TextViewで背景色や、文字色を状態別で変更したい場合にもselecterを使用しますが、
指定する属性(用途)によって<item>
タグの指定方法が異なるようです。
(異なる方法で実装すると実行時エラーが発生する)
android:textColorに指定する場合
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="#ff3f94be" /> <item android:state_selected="false" android:color="#99000000" /> </selector>
属性値としてandroid:color
として定義する。
android:backgroundに指定する場合
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" > <color android:color="#66000000" /> </item> <item android:state_selected="false"> <color android:color="#33000000" /> </item> </selector>
<color>
タグとして定義する。
selecterは、drawableの一種なので、
レイアウトxml上でdrawable
要素に対して指定しますが、
selecterのxml上でも各状態ごとに表示ファイルを分けたい場合などに、
ビットマップのdrawableを指定することがあります。
drawable
の中で更にdrawable
を指定するという点が、
まだちょっと慣れないです。。
drawable
は、種別が多いため基本的な仕組みを理解していないと、
ソースを読むときに苦労しそうです。
参考
[ソフトウェア技術ドキュメントを勝手に翻訳 7.5.3 Drawable リソース] (http://www.techdoctranslator.com/android/guide/resources/available-resources/drawable-resource)
【Android】独自Viewを作成する
最近、Androidの勉強を始めました。
Androidは、様々な要素をxmlで定義できる点が優れていると思います。 ですが、各xmlの関連とそれらをJavaソースから参照する方法を覚えるまでは、 Javaソースを見ても???となることが多々あります。。
Androidで独自のViewを作成した場合のレイアウトファイルの定義方法や、 独自の属性の作成方法について、混乱しそうなのでメモしておきたいと思います。
独自クラスのjavaファイル定義
public class CustomView extends View { public CustomView(Context context) { super(context); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } }
Viewのコンストラクタは以下の3つが存在します。
1.public View(Context context)
2.public View(Context context, AttributeSet attrs)
3.public View(Context context, AttributeSet attrs, int defStyle)
レイアウトパラメータを指定した場合、
上記2のattrs
を持つコンストラクタが利用されます。
スタイルを指定した場合、
上記3のdefStyle
を持つコンストラクタが利用されます。
レイアウトxmlでクラスを使う
<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" tools:context=".MainActivity" > <!-- [パッケージ名] + [クラス名]でタグを定義 --> <com.example.customviewsample.CustomView /> </RelativeLayout>
新しい属性の定義
標準のTextViewには、textColor
やtextSize
などの属性が予め用意されていますが、
独自Viewのなかで新たに属性を定義することができます。
どうやって(どこに)定義する?
属性は、res/values/attrs.xml
を作成し定義します。
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CustomView"> <attr name="custom_title_width" format="integer"/> </declare-styleable> </resources>
<declare-styleable>
name属性には、独自Viewのクラス名を定義する。
<attr>
name属性には、新たに定義する属性名を定義。
format属性には、属性のフォーマット名を定義する。
formatに指定できる値には下記があります。 ・integer ・float ・boolean ・string ・color ・dimension
定義した値は、どうやって使う?
独自Viewを定義したレイアウトファイルに以下のように記載します。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:myApp="http://schemas.android.com/apk/res/com.example.customviewsample” android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <!-- [パッケージ名] + [クラス名]でタグを定義 --> <com.example.customviewsample.CustomView myApp:custom_title_width="123"/> </RelativeLayout>
1.名前空間を定義する
xmlns:[名前]=“http://schemas.android.com/apk/res/[パッケージ名]“
2.属性に値をセット
myApp:custom_title_width="123"
1で定義した名前からres/values/attrs.xml
で定義した属性を参照することができます。
Javaファイルから読み込み
public class CustomView extends View { public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public CustomView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomView); int size = array.getInt(R.styleable.CustomView_custom_title_width, 3); a.recycle(); } public CustomView(Context context) { super(context); } }
コンストラクタで渡されるAttributeSet
からレイアウトファイルで定義した属性値を取得することができます。
context.obtainStyledAttributes()
は、引数にAttributeSet
とint[]
をとり、int[]はarrtibuteのid配列を指しています。
これを指定する定数は、R.styleable.[※1独自クラス名]
で参照することができます。
TypedArray
クラスのgetInt(int index, int defValue)は、
第一引数にTypedeArrayのindexを渡しますが、ここには、取得したいarrtibuteの属性のindexを指定します。
指定する定数は、R.styleable.[※1独自クラス名]_[※2属性名]
で参照することが可能です。
※1 res/values/attrs.xml
の<declare-styleable>
タグのname属性
※2 res/values/attrs.xml
の<attr>
タグのname属性
UIViewControllerのカスタム画面遷移① (モーダル遷移)
iOS7から、UIViewControllerの画面遷移を自由にカスタムできるようになりました。 今回は、UIViewControllerモーダル遷移について記載します。
遷移元ViewControllerの実装
遷移元のViewControllerにて、 UIViewControllerTransitioningDelegateを継承します。
/* アニメーションコントローラを返すメソッド(モーダルビュー表示) */ - (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { // UIViewControllerAnimatedTransitioningを継承したNSObjectを返す ※後述 return [[TransitionObject alloc] init]; } /* アニメーションコントローラを返すメソッド(モーダルビュー消去) */ - (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed { // UIViewControllerAnimatedTransitioningを継承したNSObjectを返す ※後述 return [[TransitionObject alloc] init]; }
Segueを使用した画面遷移
StroryBordのSegueを利用する場合は、アクション実装箇所で下記のようにSegueの遷移を呼び出します。
(StroryBord上は、Modal
StyleのID@“TransitionSegueId”
Segueとして定義しておきます)
- (IBAction)pushButton:(id)sender { [self performSegueWithIdentifier:@“TransitionSegueId” sender:nil]; }
prepareForSegue
では、上記で実装したtransitioningDelegate
にViewControllerを指定しておきます。
※ modalPresentationStyleは、UIModalPresentationFullScreen
またはUIModalPresentationCustom
の必要があるようです。
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { ViewController *viewController = (INRegisterFeedViewController *)segue.destinationViewController; viewController.transitioningDelegate = self; viewController.modalPresentationStyle = UIModalPresentationFullScreen; }
UIViewControllerAnimatedTransitioningの実装
上記のanimationControllerForPresentedController
にて指定しているTransitionObject
オブジェクトには、下記2つのメソッドの実装が必要となります。
/** * アニメーションにかかる時間を指定 * */ - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext { return 0.5; } /** * 画面遷移アニメーションを指定 * */ - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { // UIViewAnimationなどで任意のアニメーションを指定 }
これだけで簡単にオリジナルのアニメーションを実装できます。 アニメーションモデルを分離して書けるので、シンプルですね。
もっと高度なアニメーション制御もできるようなので、 色々と試してみたいと思います。
Unity メモ
最近Unityの勉強を始めました。 Unityは、色々と覚えることが多いのでメモに残しておきます。
RigidBody
ゲームオブジェクトに物理計算をつける
Component > Physics から RigidBody
と追加
重力を無効にする
Use Gravity
のチェックを外す
ゲームオブジェクトに特定方向に動かさないようにする
インスペクター RigidBody
> Constaints
Freeze Rotation
=> 回転を抑止
Freeze Position
=> 移動を抑止
ゲームオブジェクトの重力を変更する
インスペクター RigidBody
> Mass
値が小さいと運動の影響を受けやすくなる (例) なにかと衝突したときに大きく跳ねさせたい => 小さくする
よく使うメソッド
AddForce(force: Vector3)
RigidBodyに力を追加して移動させる
他のオブジェクトからは物理的影響をうけないオブジェクトに設定
Is Kinematic
を有効にする
他のオブジェクトには物理的影響を与えるが、 他のオブジェクトからは物理的影響をうけないオブジェクトになる
※注意 RigidbodyのIsKinematicがTrue ColliderのIsTriggerがTrue に設定しないとOnCollisionがコールされない。
Physic Material
反射や摩擦などの物理運動の値を設定
ゲームオブジェクトを跳ねやすくする
[Physic Material] > Bounciness
を変更
大きい程はねやすい
[GameObject]インスペクタ > Sphere Collider
> Material
に設定したPhysic Materialを設定
反発係数の評価方式を設定する
BounceCombine・・・反発係数が大きい方の評価係数が適用
ゲーム全体の設定
重力を変更する
Edit
> Project Settings
> Physic
Gravity
※デフォルトは「9.8」 この時の物理運動は、1.0が1メートルになる。 大きさ1.0に対して直径1メートルの物質をみているのと同じ。
MonoDevelopを使ってUnityでデバッグする
1.エディタをMonoDevelopにする(Preferences – External Script Editor) 2.UnityのメニューからAssets – Sync MonoDevelop Projectをクリック 3.MonoDevelopが起動したらツールバーにあるAttach to Processのアイコンをクリック 4.Unityが起動していればリストに出てくるので選択してAttachをクリック 5.MonoDevelopでスクリプトのソースを開いて適当な位置にブレークポイントを置く 6.Unity側でプレビューを実行 7.ブレークポイントの位置で止まるので、ツールバーからステップ実行とかする
その他
プレハブの変更をその他のプレハブへ反映させる
値を変更 > インスペクタ
> Prefab > Apply