2月 27

昨日の続きです。昨日は Activity の切替を overridePendingTransition を使って Activity の遷移にアニメーション効果を付ける方法を書きましたが、今日は同じことを View で行う方法を記載します。

複数の View を切替えるには ViewAnimator を使うのが便利です。似た機能を持つクラスで ViewFlipper と ViewSwitcher がありますが、ViewFliper は定期的にビューを自動的に切替える機能が追加したクラスで、ViewSwitcher は2枚の View に特化したクラスです。ここでは ViewAnimator を使います。

この手法の長所はシステム設定(アニメーション設定)に影響を受けないことです、一方、画面レイアウトや実装が複雑になってしまうかもしれません。

サンプルコード

サンプルアプリの仕様は機能と同じです。ただし、Activity は1枚なので Back キーを押すと全画面に戻るのではなくアプリを終了します。overridePendingTransition を使った場合は、アニメーションはリソース(xml ファイル)でしか指定できませんが ViewAnimator ではコードでアニメーションを定義することができます。サンプルコードではコードで定義したものを用いていますがリソースを使う場合はコード中のコメントアウトした部分を有効にしリソースを前回のサンプルコードで用いたものを使用するように変更します。

src/sak/samples/MyActivityBase.java

abstract public class MyActivityBase extends Activity {

    private static final int THRESHOLD_DISTANCE = 120;
    private static final int THRESHOLD_OPPOSITION_AXIS = 250;
    private static final int THRESHOLD_VELOCITY = 200;
   
    private GestureDetector mGestureDetector;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGestureDetector = new GestureDetector(new MyGestureListener());
    }
   
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mGestureDetector.onTouchEvent(event))
            return true;
        else
            return false;
    }
   
    /*
     * true なら上下方向、false なら左右方向の画面遷移をする。
     */

    protected boolean slideUpdown = true;
   
    private class MyGestureListener extends SimpleOnGestureListener {
        @Override
        public boolean onFling(
                MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
           
            float dX = e2.getX() - e1.getX();
            float dY = e2.getY() - e1.getY();
           
            float velocity = Math.abs(slideUpdown ? velocityY : velocityX);
            float diff = slideUpdown ? dY : dX;
            float opposition_axis = Math.abs(slideUpdown ? dX : dY);
           
            if (opposition_axis > THRESHOLD_OPPOSITION_AXIS)
                return false;
           
            if (-diff > THRESHOLD_DISTANCE && velocity > THRESHOLD_VELOCITY)
                next();
            else if (diff > THRESHOLD_DISTANCE && velocity > THRESHOLD_VELOCITY)
                back();
               
            return false;
        }
    }
   
    abstract protected void next();
   
    protected void back() {
        finish();
    }
}

src/sak/samples/ViewTransitionEffectDemo.java

public class ViewTransitionEffectDemo extends MyActivityBase {
   
    private static final int TEXT_SIZE = 64;
    private static final int TEXT_COLOR  = Color.argb(0xff, 0xff, 0xff, 0xff);  // 白
    private static final int COLOR_GRAY  = Color.argb(0xff, 0x88, 0x88, 0x88);  // 灰
    private static final int COLOR_RED   = Color.argb(0xff, 0xff, 0x00, 0x00);  // 赤
    private static final int COLOR_GREEN = Color.argb(0xff, 0x00, 0xff, 0x00);  // 緑
    private static final int COLOR_BLUE  = Color.argb(0xff, 0x00, 0x00, 0xff);  // 青

    private Animation nextIn;
    private Animation nextOut;
    private Animation prevIn;
    private Animation prevOut;
   
    private ViewAnimator va;
    private int page = 0;
   
    private static int ANIM_MODE = Animation.RELATIVE_TO_PARENT;
    private static int ANIM_DURATION = 300;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (!slideUpdown) {
            nextIn  = new TranslateAnimation(
                    ANIM_MODE, 1f, ANIM_MODE, 0f, ANIM_MODE, 0f, ANIM_MODE, 0f);
            nextOut = new TranslateAnimation(
                    ANIM_MODE, 0f, ANIM_MODE, -1f, ANIM_MODE, 0f, ANIM_MODE, 0f);
            prevIn  = new TranslateAnimation(
                    ANIM_MODE, -1f, ANIM_MODE, 0f, ANIM_MODE, 0f, ANIM_MODE, 0f);
            prevOut = new TranslateAnimation(
                    ANIM_MODE, 0f, ANIM_MODE, 1f, ANIM_MODE, 0f, ANIM_MODE, 0f);
           
        } else {
            nextIn  = new TranslateAnimation(
                    ANIM_MODE, 0f, ANIM_MODE, 0f, ANIM_MODE, 1f, ANIM_MODE, 0f);
            nextOut = new TranslateAnimation(
                    ANIM_MODE, 0f, ANIM_MODE, 0f, ANIM_MODE, 0f, ANIM_MODE, -1f);
            prevIn  = new TranslateAnimation(
                    ANIM_MODE, 0f, ANIM_MODE, 0f, ANIM_MODE, -1f, ANIM_MODE, 0f);
            prevOut = new TranslateAnimation(
                    ANIM_MODE, 0f, ANIM_MODE, 0f, ANIM_MODE, 0f, ANIM_MODE, 1f);
            // リソースを使用する場合はこちらを使用する
        }
       
        nextIn.setDuration(ANIM_DURATION);
        nextOut.setDuration(ANIM_DURATION);
        prevIn.setDuration(ANIM_DURATION);
        prevOut.setDuration(ANIM_DURATION);
       
        // リソースを使用する場合はこちらを使用する
//        if (!slideUpdown) {
//          nextIn = AnimationUtils.loadAnimation(this, R.anim.push_left_in);
//          nextOut = AnimationUtils.loadAnimation(this, R.anim.push_left_out);
//          prevIn = AnimationUtils.loadAnimation(this, R.anim.push_right_in);
//          prevOut = AnimationUtils.loadAnimation(this, R.anim.push_right_out);
//         
//        } else {
//          nextIn = AnimationUtils.loadAnimation(this, R.anim.push_up_in);
//          nextOut = AnimationUtils.loadAnimation(this, R.anim.push_up_out);
//          prevIn = AnimationUtils.loadAnimation(this, R.anim.push_down_in);
//          prevOut = AnimationUtils.loadAnimation(this, R.anim.push_down_out);
//        }
       
        va = new ViewAnimator(this);
        va.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
       
        va.addView(createTextView("0", COLOR_GRAY));
        va.addView(createTextView("1", COLOR_RED));
        va.addView(createTextView("2", COLOR_GREEN));
        va.addView(createTextView("3", COLOR_BLUE));
       
        setContentView(va);
    }

    private TextView createTextView(String text, int background) {
        TextView tv = new TextView(this);
        tv.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tv.setGravity(Gravity.CENTER);
        tv.setText(text);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE);
        tv.setTextColor(TEXT_COLOR);
        tv.setBackgroundColor(background);

        return tv;
    }
   
    @Override
    protected void next() {
        if (page < va.getChildCount() - 1) {
            va.setInAnimation(nextIn);
            va.setOutAnimation(nextOut);
            va.showNext();
            page ++;
        } else {
            Toast.makeText(this, "最後のページです。", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void back() {
        if (page > 0) {
            va.setInAnimation(prevIn);
            va.setOutAnimation(prevOut);
            va.showPrevious();
            page --;
        } else {
            Toast.makeText(this, "最初のページです。", Toast.LENGTH_SHORT).show();
        }
    }
}


Posted by sak+

Tagged with:
2月 26

前回に引き続き、技術ネタです。これまでに取得した Andorid に関するノウハウを忘れないうちに記録しちゃいます。

さて、表題に挙げた overridePendingTransition。使った事(聞いた事)ありますか?
overridePendingTransition は Activity 間の遷移にアニメーション効果を加えることができる Activity クラスのメソッドです。API Level 5 で追加されたメソッドなので Android 2.0 以降で使用可能です。

使い方は簡単で startActivity() または finish() の後でこのメソッドをコールするだけです。(後ってとこが重要なので間違えないように!)指定するのは今の画面を閉じるアニメーションと次の画面を開くアニメーションでいずれもリソースで定義したアニメーションのリソースIDを指定します。プログラムで作成したアニメーションを使用できないのが残念ですね。

なお、画面遷移でのアニメーション効果を有効にするためには、システム設定の「画面設定」>「アニメーション表示」で「すべてのアニメーション」にチェックが入っている必要があります。端末の初期状態では「一部のアニメーション」にチェックを入っていることが多いようですがこの状態ではアニメーション効果は有効ではありません。試す前には必ずこの設定が「すべてのアニメーション」になっていることを確認してください。

device-0s.png

使用例

この機能を使えば iPhone の典型的なアプリケーション(進む場合は右方向へのスライド、戻る場合は左方向へのスライド)のような画面遷移を持つ Android アプリケーションを作成することができます。

サンプルコード

ここでは4つの画面(Activity)を持つアプリケーションを例に挙げます。画面の遷移は左右のフリックで行います。画面の遷移は左右のスライドアニメーションで行っています。プログラム中にフラグを設けており、その設定を変更することでフリック動作および画面遷移の方向を左右でなく上下に変更できるようになっています。

device-1s.png device-2s.png

device-3s.png device-4s.png

res/anim/push_left_in.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="100%p"
    android:toXDelta="0"
    android:duration="300"/>

res/anim/push_left_out.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0"
    android:toXDelta="-100%p"
    android:duration="300"/>

res/anim/push_right_in.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="-100%p"
    android:toXDelta="0"
    android:duration="300"/>

res/anim/push_right_out.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0"
    android:toXDelta="100%p"
    android:duration="300"/>

res/anim/push_down_in.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromYDelta="-100%p"
    android:toYDelta="0"
    android:duration="300"/>

res/anim/push_down_out.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromYDelta="0"
    android:toYDelta="100%p"
    android:duration="300"/>

res/anim/push_up_in.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromYDelta="100%p"
    android:toYDelta="0"
    android:duration="300"/>

res/anim/push_up_out.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromYDelta="0"
    android:toYDelta="-100%p"
    android:duration="300"/>

src/sak/samples/MyActivityBase.java

全ての Activity の親となる抽象クラスです。overridePendingTransition はこの中で使用しています。画面遷移では GestureDetector を使用していますが、それもこのクラスの中で定義しています。という訳でこのアプリの重要な部分はこのクラスにほぼ全て集約されています。その他の子クラスでは画面表示と最小限の固有設定をオーバライドすれば良いように設計されています。

abstract public class MyActivityBase extends Activity {

    private static final int THRESHOLD_DISTANCE = 120;
    private static final int THRESHOLD_OPPOSITION_AXIS = 250;
    private static final int THRESHOLD_VELOCITY = 200;
   
    private GestureDetector mGestureDetector;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGestureDetector = new GestureDetector(new MyGestureListener());
    }
   
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mGestureDetector.onTouchEvent(event))
            return true;
        else
            return false;
    }
   
    /*
     * true なら上下方向、false なら左右方向の画面遷移をする。
     */

    boolean slideUpdown = false;
   
    private class MyGestureListener extends SimpleOnGestureListener {
        @Override
        public boolean onFling(
                MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
           
            float dX = e2.getX() - e1.getX();
            float dY = e2.getY() - e1.getY();
           
            float velocity = Math.abs(slideUpdown ? velocityY : velocityX);
            float diff = slideUpdown ? dY : dX;
            float opposition_axis = Math.abs(slideUpdown ? dX : dY);
           
            if (opposition_axis > THRESHOLD_OPPOSITION_AXIS)
                return false;
           
            if (-diff > THRESHOLD_DISTANCE && velocity > THRESHOLD_VELOCITY)
                next();
            else if (diff > THRESHOLD_DISTANCE && velocity > THRESHOLD_VELOCITY)
                back();
               
            return false;
        }
    }
   
    abstract protected void next();
   
    protected void back() {
        finish();
    }
   
    protected void showNext(Intent intent, int flags) {
        flags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        flags |= Intent.FLAG_ACTIVITY_CLEAR_TOP;
        intent.setFlags(flags);
        startActivity(intent);
        if (slideUpdown)
            overridePendingTransition(R.anim.push_up_in, R.anim.push_up_out);
        else
            overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out);
    }
   
    protected void showPrev(Intent intent, int flags) {
        finish();
    }
   
    @Override
    public void finish() {
        super.finish();
        if (slideUpdown)
            overridePendingTransition(R.anim.push_down_in, R.anim.push_down_out);
        else
            overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out);
    }
}

src/sak/samples/ActivityTransitionEffectDemo.java

public class ActivityTransitionEffectDemo extends MyActivityBase {
   
    private static final String TEXT = "0";
    private static final int TEXT_SIZE = 64;
    private static final int TEXT_COLOR = Color.argb(0xff, 0xff, 0xff, 0xff);   // 白
    private static final int BACK_COLOR = Color.argb(0xff, 0x88, 0x88, 0x88);   // 灰

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TextView tv = new TextView(this);
        tv.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tv.setGravity(Gravity.CENTER);
        tv.setText(TEXT);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE);
        tv.setTextColor(TEXT_COLOR);
        tv.setBackgroundColor(BACK_COLOR);
        setContentView(tv);
    }
   
    @Override
    protected void next() {
        Intent intent = new Intent(this, Activity1.class);
        super.showNext(intent, 0);
    }

    @Override
    protected void back() {
        Toast.makeText(this, "最初のページです。", Toast.LENGTH_SHORT).show();
    }
}

src/sak/samples/Activity1.java

public class Activity1 extends MyActivityBase {

    private static final String TEXT = "1";
    private static final int TEXT_SIZE = 64;
    private static final int TEXT_COLOR = Color.argb(0xff, 0xff, 0xff, 0xff);   // 白
    private static final int BACK_COLOR = Color.argb(0xff, 0xff, 0x00, 0x00);   // 赤
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        TextView tv = new TextView(this);
        tv.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tv.setGravity(Gravity.CENTER);
        tv.setText(TEXT);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE);
        tv.setTextColor(TEXT_COLOR);
        tv.setBackgroundColor(BACK_COLOR);
        setContentView(tv);
    }

    @Override
    protected void next() {
        Intent intent = new Intent(this, Activity2.class);
        super.showNext(intent, 0);
    }
}

src/sak/samples/Activity2.java

public class Activity2 extends MyActivityBase {

    private static final String TEXT = "2";
    private static final int TEXT_SIZE = 64;
    private static final int TEXT_COLOR = Color.argb(0xff, 0xff, 0xff, 0xff);   // 白
    private static final int BACK_COLOR = Color.argb(0xff, 0x00, 0xff, 0x00);   // 緑
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        TextView tv = new TextView(this);
        tv.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tv.setGravity(Gravity.CENTER);
        tv.setText(TEXT);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE);
        tv.setTextColor(TEXT_COLOR);
        tv.setBackgroundColor(BACK_COLOR);
        setContentView(tv);
    }
   
    @Override
    protected void next() {
        Intent intent = new Intent(this, Activity3.class);
        super.showNext(intent, 0);
    }
}

src/sak/samples/Activity3.java

public class Activity3 extends MyActivityBase {

    private static final String TEXT = "3";
    private static final int TEXT_SIZE = 64;
    private static final int TEXT_COLOR = Color.argb(0xff, 0xff, 0xff, 0xff);   // 白
    private static final int BACK_COLOR = Color.argb(0xff, 0x00, 0x00, 0xff);   // 青
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        TextView tv = new TextView(this);
        tv.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tv.setGravity(Gravity.CENTER);
        tv.setText(TEXT);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE);
        tv.setTextColor(TEXT_COLOR);
        tv.setBackgroundColor(BACK_COLOR);
        setContentView(tv);
    }
   
    @Override
    protected void next() {
        Toast.makeText(this, "最後のページです。", Toast.LENGTH_SHORT).show();
    }
}


Posted by sak+

Tagged with:
2月 20

AndroidManifest.xml ファイル内で使用できるタグに activity-alias というのがあるが、どんな場合に使用するかがようやく分かったのでメモる。

3つのタブを持つ画面を考えてみよう。そして3つのタブにはそれぞれ別の Activity が割り当てられている。すなわち、こんな画面。

device-1s.png

device-2s.png

device-3s.png

このアプリは起動するとタブ1を開いて起動する。では、このアプリでタブ2またはタブ3を開いた状態で起動させたい場合にはどうしたら良いだろう?

こんな時に使用するのが今回取り上げる activity-alias タグです。

要するに actvity-alias は、実際に呼ぶ Activity に状態を切替えるための付加情報を追加したエントリポイントを作成できるタグです。実際に呼ぶ Activity は android:targetActivity 属性で指定し、付加情報としては android:name 属性を使用します。

すなわち activity-alias タグで指定された設定を使用する場合、android:targetActivity で指定した Activity を起動しその内部で android:name の内容によって状態を切替える処理(この場合は指定されたタブを表示する処理)を行うのです。

ここで挙げる例ではラウンチャーから起動するエントリポイントを追加する例ですが、インテントフィルターの中身を書き換えるとラウンチャーからだけではなく外部アプリからも起動できるようになります。

例えば拙作『CF電話帳』では、ラウンチャーからの起動や ACTION_CALL_BUTTON からは「連絡先」タブを開いて起動していますが、ACTION_DIAL で呼ばれた場合は「電話」タブを開くように制御するために使用しています。

device-4s.png device-5s.png

以下にサンプルコードを用意しました。参考にどうぞ。

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="sak.samples"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="7" />

    <application android:icon="@drawable/icon" android:label="activity-alias Demo">
        <activity android:name=".ActivityAliasDemo">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".Activity1" />
        <activity android:name=".Activity2" />
        <activity android:name=".Activity3" />
       
        <!-- タブ3を開くエントリポイント -->
        <activity-alias
            android:name=".Activity3Alias"
            android:targetActivity=".ActivityAliasDemo"
            android:label="activity-alias デモ">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
       
    </application>
</manifest>

src/sak/samples/ActivityAliasDemo.java

public class ActivityAliasDemo extends TabActivity {

    private static final String TAB_1 = "sak.samples.Activity1Alias";
    private static final String TAB_2 = "sak.samples.Activity2Alias";
    private static final String TAB_3 = "sak.samples.Activity3Alias";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        final TabHost tabHost = getTabHost();
       
        tabHost.addTab(tabHost.newTabSpec(TAB_1)
                .setIndicator("タブ 1")
                .setContent(new Intent(this, Activity1.class)));

        tabHost.addTab(tabHost.newTabSpec(TAB_2)
                .setIndicator("タブ 2")
                .setContent(new Intent(this, Activity2.class)));

        tabHost.addTab(tabHost.newTabSpec(TAB_3)
                .setIndicator("タブ 3")
                .setContent(new Intent(this, Activity3.class)));
       
        String componentName = getIntent().getComponent().getClassName();
        if (TAB_1.equals(componentName)) {
            tabHost.setCurrentTabByTag(TAB_1);
        } else if (TAB_2.equals(componentName)) {
            tabHost.setCurrentTabByTag(TAB_2);
        } else if (TAB_3.equals(componentName)) {
            tabHost.setCurrentTabByTag(TAB_3);
        } else {
            tabHost.setCurrentTabByTag(TAB_1);
        }
    }
}

src/sak/samples/Activity1.java

public class Activity1 extends Activity {

    private static final String TEXT = "1";
    private static final int TEXT_SIZE = 64;
    private static final int TEXT_COLOR = Color.argb(0xff, 0xff, 0xff, 0xff);   // 白
    private static final int BACK_COLOR = Color.argb(0xff, 0xff, 0x00, 0x00);   // 赤
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        TextView tv = new TextView(this);
        tv.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tv.setGravity(Gravity.CENTER);
        tv.setText(TEXT);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE);
        tv.setTextColor(TEXT_COLOR);
        tv.setBackgroundColor(BACK_COLOR);
        setContentView(tv);
    }
}

src/sak/samples/Activity2.java

public class Activity2 extends Activity {

    private static final String TEXT = "2";
    private static final int TEXT_SIZE = 64;
    private static final int TEXT_COLOR = Color.argb(0xff, 0xff, 0xff, 0xff);   // 白
    private static final int BACK_COLOR = Color.argb(0xff, 0x00, 0xff, 0x00);   // 緑
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        TextView tv = new TextView(this);
        tv.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tv.setGravity(Gravity.CENTER);
        tv.setText(TEXT);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE);
        tv.setTextColor(TEXT_COLOR);
        tv.setBackgroundColor(BACK_COLOR);
        setContentView(tv);
    }
}

src/sak/samples/Activity3.java

public class Activity3 extends Activity {

    private static final String TEXT = "3";
    private static final int TEXT_SIZE = 64;
    private static final int TEXT_COLOR = Color.argb(0xff, 0xff, 0xff, 0xff);   // 白
    private static final int BACK_COLOR = Color.argb(0xff, 0x00, 0x00, 0xff);   // 青
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        TextView tv = new TextView(this);
        tv.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tv.setGravity(Gravity.CENTER);
        tv.setText(TEXT);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, TEXT_SIZE);
        tv.setTextColor(TEXT_COLOR);
        tv.setBackgroundColor(BACK_COLOR);
        setContentView(tv);
    }
}


Posted by sak+

Tagged with:
2月 19
昨日(2/18)の夜「ユースト、ニコ生など動画配信系に関しての勉強会」に参加してきました。主催はぽんぽこバレーと呼ばれている札幌の狸小路近辺にオフィスを構える会社が中心の謎の集団w。場所は初音ミクで有名なクリプトン・フューチャー・メディアさんの会議室です。

今回は『札幌の今(6時間以内に札幌で開催されるイベント情報)』を伝える sapporo6h の服部さんに動画配信の現在、未来のお話しを伺いました。内容は UST でも配信されました。



Video streaming by Ustream

会議自体もとてもおもしろいのですが、このイベントはその後の飲み会がとても楽しいんです。sapporo6h の服部さんや勉強会に参加した方々といろんな話しをして良い刺激をもらいました。クリプトンの伊藤代表とも名刺交換をさせてもらいました。


Posted by sak+

2月 14

昨日のエントリでも軽く触れましたが拙作『CF電話帳』が絶賛 Softbank ピックアップに掲載中です。私は普段はドコモユーザで Softbank ピックアップってなにかはあまり詳しくないのですがたまたま Softbank 003SH を借用中のため試す事ができました。

Softbank ピックアップって Android Market のタブの一番右が『Softbank』タブになるのですね。私の持っている Xperia では『マイアプリ』タブになっている部分です。ここを押すと Softbank の選んだお勧めアプリの一覧が表示されます。私のアプリもいますね。評価が今ひとつなのはご愛嬌ですw

  sb-pickup01.png sb-pickup02.png

まだ『CF電話帳』お試しでないあなた!この機会にどうぞお試しください!


Posted by sak+

2月 13

『CF電話帳』公開して2ヶ月あまり経ちました。これまで業務多忙でなかなかバージョンアップをする時間が確保できませんでしたが、ようやく一段落したのでこの3連休を使いバージョンアップを行いました。

今回のバージョンアップで変更のあった機能は以下の2つです。

  • タブ・インターフェースを採用
  • ダイヤラ画面を追加

 cfd-0.png cfd-1.png

標準の電話帳の多くを見てもわかるようにダイヤラ画面、通話履歴、連絡先の切替をタブで切替えることができると非常に便利です。これまで技術的な理由によりなかなか採用ができていませんでしたが、なんとか解決することができたため採用しました。この際、自前のダイヤラ画面がなかったため追加しました。見栄えはそんなに変わっていませんが、作りが大きく変わっていますのでバージョン番号も思い切って 2.0 にアップさせました。

ちょうど今、(2月11日〜2月18日の予定)で Softbank ピックアップでも紹介していただいています。まだ、ご使用でない方もこの機会にお試しを!!


Posted by sak+

Tagged with:
2月 06
といっても、「はてなB Lite」の公開を停止するわけではありません。

とうとう本家から「はてなブックマーク」が登場しましたので、歴史的な(ちょっと大げさw)役割を終了しましたねというお話しでした。

hatena-honke.png

拙作「はてなB Lite」は私にとっては3番目の Android アプリケーションです。 2009/06/08 にマーケットに公開しました。考えてみれば日本での初めての Android の端末(HT-03A)発売前のことなのですね。Android アプリがまだ多くなかった時代だったせいか多くのメディアで紹介していただけてありがたかったです。モチベーションの原動力になりました。

当時、Andorid の勉強をしていた私はクラウドとスマートフォンの連携が可能な Atom Pub API に興味を持っており、その API を公開していたはてなブックマークに目をつけました。もちろん本家が手を出していないのを確認してからw

Lite を付けたのはその後の有料化を睨んでのものだったのですが、思っていたよりダウンロード数が伸びなかったのとマーケットの有料化の遅れ、そしてライバルソフトのデキの良さなどもあり、モチベーションが低下し実現には至りませんでした。

今回の本家からの「はてなブックマーク」アプリ登場という出来事は「はてなB Lite」公開当時の話しを思い出す良いきっかけになりました。


Posted by sak+

preload preload preload