2007/03/04開始。ソフトウェア管理やDelerer SEの作者であるおにぎりくんの試行錯誤の記録です。
- [Vue.js]時計?タイムコードを表示するWebアプリ
- (2021/11/16)
- ポエム
- (2020/09/30)
- メトロノームアプリをリリース
- (2017/04/22)
- Sikulix勉強中:便利関数
- (2017/02/25)
- [JavaFX]学習メモ
- (2016/09/22)
ダイアログのためにxmlを書くのは嫌なので、 コードで書く方法を調べた。
Android : How to update the selector(StateListDrawable) programmatically
ここによると、StateListDrawableクラスを作成し、addStateメソッドでDrawableオブジェクトを追加してくださいとのこと。状態はandroid.R.attr.state_hogehogeで指定するのだが、何もない状態はマイナスにするといいらしい。
PR
前回の記事のものに手を加えました。縦横の画面サイズ切り替えで表示を維持したり、コードからビューを追加してみたりしています。また、名前がアレだったので直しました。
プロジェクト一式ダウンロード
HorizontalPageScrollView.java
package fsoriented.sample.horizontalscroll;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.OnGestureListener;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
/**
* ページごとにスナップする横方向のスクロールビュー。
*
* フリック(flingイベント)によって、隣のページにスナップする。
* ドラッグ(upイベント)によって、一番近いページにスナップする。
*
* Gelleryでも似たようなことができそうなんだけど。。。
*
* 内部にLinearLayout(horizontal)を持たせることを期待している。
* LinearLayout直下のビューをページとし、勝手にサイズを変更する。
*
* 参考:
* - http://www.adamrocker.com/blog/292/we-are-the-speaker-of-google-devfest-2010-japan.html
* - http://blog.global-eng.co.jp/android/2011/02/18/horizontalscrollviewにイージングをつける方法/
* - http://android.keicode.com/basics/ui-custom-horizontalscrollview.php
*
* @author LapisCactus
*
*/
public class HorizontalPageScrollView extends HorizontalScrollView implements OnGestureListener {
/** フリックを検出するオブジェクト */
private GestureDetector detector;
/** フリックとみなさない速度の閾値 */
private final float velocityThreshold = 100f;
/** 現在のページ */
private int currentPage = 0;
/** ページ遷移時に呼ばれるリスナー。nullなら呼ばない。 */
private OnPageChangeListener listener = null;
/**
* コンストラクタ
*
* @param context
*/
public HorizontalPageScrollView(Context context) {
super(context);
initialize(context);
}
/**
* コンストラクタ
*
* @param context
* @param attrs
*/
public HorizontalPageScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context);
}
// フリックを検出するオブジェクトを生成する
private void initialize(Context context) {
detector = new GestureDetector(context, this);
this.setFadingEdgeLength(0);
this.setHorizontalScrollBarEnabled(false);
}
/**
* 現在表示されているページ番号を返す
*
* @return ページ番号
*/
public int getCurrentPage() {
return currentPage;
}
/**
* 指定したページを表示する
*
* @param page
* ページ番号
* @param event
* ページ遷移イベントを発生させるかどうか
*/
public void setCurrentPage(int page, boolean event) {
// サイズが確定していれば、表示位置を移動する
int viewWidth = this.getWidth();
if (viewWidth != 0) {
scrollTo(page * viewWidth, 0);
}
// 現在ページを更新する。サイズが未確定なら、確定時イベント(onLayout)で現在ページへ移動する
currentPage = page;
// ページ遷移イベントを送信する
if (event && listener != null) {
listener.onPageChanged(currentPage, ((LinearLayout) getChildAt(0))
.getChildAt(currentPage));
}
}
/**
* ページ遷移時に呼ばれるリスナーを登録する。
*
* @param listener
*/
public void setOnPageChangedListener(OnPageChangeListener listener) {
this.listener = listener;
}
// ビューのサイズが変更されたときの処理
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// ページの幅と高さを設定する
int count = ((LinearLayout) getChildAt(0)).getChildCount();
for (int i = 0; i < count; i++) {
((LinearLayout) getChildAt(0)).getChildAt(i).setLayoutParams(
new android.widget.LinearLayout.LayoutParams(w, h));
}
}
// レイアウトされたときの処理
// currentPageの適用はここで行う。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
// カレントページに移動
int w = r - l;
smoothScrollTo(currentPage * w, 0);
}
// 画面にタッチしたときの処理
@Override
public boolean onTouchEvent(MotionEvent event) {
// フリック判定を優先して行う
if (detector.onTouchEvent(event))
return true;
// フリックでなければ、指が離れたイベントを使用する
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
// もっとも近い境界へスナップする
int currentx = this.getScrollX();
int viewWidth = this.getWidth();
int destPage = (currentx + viewWidth / 2) / viewWidth;
smoothScrollTo(destPage * viewWidth, 0);
if (currentPage != destPage) {
currentPage = destPage;
listener.onPageChanged(currentPage, ((LinearLayout) getChildAt(0))
.getChildAt(currentPage));
}
return true;
}
// そのほかはデフォルト
return super.onTouchEvent(event);
}
// フリック時の処理
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// フリックなら隣に移動
int currentx = this.getScrollX();
int viewWidth = this.getWidth();
if (velocityX < -velocityThreshold) {
// 右ページ
int destPage = currentx / viewWidth + 1;
smoothScrollTo(destPage * viewWidth, 0);
if (destPage < ((LinearLayout) getChildAt(0)).getChildCount()) {
currentPage = destPage;
listener.onPageChanged(currentPage, ((LinearLayout) getChildAt(0))
.getChildAt(currentPage));
}
return true;
} else if (velocityX > velocityThreshold) {
// 左ページ
int destPage = currentx / viewWidth;
smoothScrollTo(destPage * viewWidth, 0);
if (destPage >= 0 && destPage != currentPage) {
currentPage = destPage;
listener.onPageChanged(currentPage, ((LinearLayout) getChildAt(0))
.getChildAt(currentPage));
}
return true;
}
return false;
}
// 不使用
public boolean onDown(MotionEvent e) {
return false;
}
// 不使用
public void onLongPress(MotionEvent e) {
}
// 不使用
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
// 不使用
public void onShowPress(MotionEvent e) {
}
// 不使用
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
/**
* フリックやドラッグにより、ページが遷移したときに呼ばれるコールバック定義
*
* @author LapisCactus
*
*/
public static interface OnPageChangeListener {
/**
* ページが遷移したときの処理
*
* @param pageIndex
* ページ番号(0~)
* @param showing
* 表示中のViewオブジェクト
*/
public abstract void onPageChanged(int pageIndex, View showing);
}
}
ギャラリーのような横スクロールビューです。 ページごとにスナップします。
プロジェクトファイルダウンロード
2011/05/06追記:ファイルを差し替えました。新しく記事を書きました(ページ毎にスナップする横スクロールビュー(2))。
フォントを読み込むサンプル。 意外と簡単にフォントを読み込んでくれる。
MainActivity.java
package sample.customfont;
import java.io.File;
import android.app.Activity;
import android.graphics.Typeface;
import android.os.Bundle;
import android.widget.TextView;
/**
* フォントをSDカードから読み込み、TextViewに適用するサンプル。
*
* フォントファイルをファイルパスで指定し、読み込む。
* ファイルが見つからなければ、フォントを適用しない。
* フォントファイルの読み込みは簡単で、ただ
* Typeface.createFromFile(File)
* を使うだけである。
* ファイルが読み込めないときに、例外RuntimeExceptionが投げられる。
* E/AndroidRuntime( 1000): java.lang.RuntimeException:
* Unable to start activity ComponentInfo{sample.customfont/sample.customfont.MainActivity}:
* java.lang.RuntimeException: native typeface cannot be made
* (DDMSを使ってフォントファイルを転送しようとしたが、失敗していたため例外が起きた。
* adb pushを使うと上手くいくのだが。。。)
*
* @author LapisCactus
*
*/
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// load UI widgets
TextView textview = (TextView) findViewById(R.id.main_text);
// load a font and apply it to a TextView
File file = new File("/mnt/sdcard/fonts/KozGoPro-Light.otf");
System.out.println("exists: " + file.exists());
System.out.println("canRead: " + file.canRead());
if (file.exists() && file.canRead()) {
Typeface tf = Typeface.createFromFile(file);
textview.setTypeface(tf);
}
}
}
Android記事へのリンク
導入と日常的に使うもの。
公式リファレンス(内容は英語)
http://developer.android.com/intl/ja/reference/packages.html>右上の検索ボックスにクラス名入力+出てくる候補クリック
スポンサード・リンク
フリーソフト指向::開発日記 by LapisCactus
