2012年7月28日土曜日

秒数無しのDigitalClock作成

チームEggの赤峰です。

さて、本日はDigitalClockの話です。
ネイティブのViewにDigitalClockというものがあります。
これを利用することで、時間を簡単に表示することができます。


しかし、DigitalClockではフォーマット指定により秒数が必ず表示されます。
秒数が非表示のDigitalClockを利用する場合は、
オリジナルDigitalClockを自作することになります。

以下が秒数を非表示にしたオリジナルのDigitalClockです。
SimpleDigitalClock.java
package com.example.digitalclock;

import java.util.Calendar;

import android.content.Context;
import android.os.Handler;
import android.os.SystemClock;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.widget.TextView;

public class SimpleDigitalClock extends TextView {
    private Calendar mCalendar;
    private Runnable mTicker;
    private Handler mHandler;
    private boolean mTickerStopped = false;
    private static final String FORMAT = "k:mm";

    public SimpleDigitalClock(Context context) {
        super(context);
        initClock();
    }

    public SimpleDigitalClock(Context context, AttributeSet attrs) {
        super(context, attrs);
        initClock();
    }

    private void initClock() {
        if (mCalendar == null) {
            mCalendar = Calendar.getInstance();
        }
    }

    @Override
    protected void onAttachedToWindow() {
        // ViewがWindowにアタッチされたとき(結合したとき)に呼び出される。
        mTickerStopped = false;
        super.onAttachedToWindow();
        mHandler = new Handler();

        mTicker = new Runnable() {
            @Override
            public void run() {
                if (mTickerStopped)
                    return;
                mCalendar.setTimeInMillis(System.currentTimeMillis());
                setText(DateFormat.format(FORMAT, mCalendar));
                invalidate();
                long now = SystemClock.uptimeMillis();
                long next = now + (1000 - now % 1000);
                mHandler.postAtTime(mTicker, next);
            }
        };
        mTicker.run();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mTickerStopped = true;
    }
}

次に独自ViewをXMLで読み込みます。 activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <com.example.digitalclock.SimpleDigitalClock
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:textSize="50dp" />
</LinearLayout>

以上で、秒数無しのDigitalClockを利用可能になります。
表示フォーマットを変更したい場合は、SimpleDigitalClockのFORMATを修正してください

2012年7月25日水曜日

Jerry Bean(4.1)からNotification通知でアプリが落ちる

NotificationにNotification.DEFAULT_VIBRATEを設定している場合。
.setDefaults(Notification.DEFAULT_VIBRATE)
このような場合にパーミッションの影響でアプリが落ちる場合があります。
その場合、バイブレーションのパーミッションを設定してあげることで解決します。
<uses-permission android:name="android.permission.VIBRATE" />

2012年7月22日日曜日

CheckboxとSwitchをバージョンごとに切り替える

チームEggの曽川です。

本日からチームメンバーとちょっとずつ更新していきます。
よろしくお願いします。

さて、本日はSwitchの話です。
ICSからSwitchというUIが新しく導入されました。
以前はCheckboxを使用していましたが、SwitchはよりリッチなUIであるため、ICS以降ではSwitchが使われることが多いようです。
では、ICSとそれ以前のアプリでの切り替え方法です。
まず、resのlayoutにCheckboxで定義したXMLを記述します。
widget_profile_onoff.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <!-- アーティストについて -->
    <CheckBox
        android:id="@id/profile_artist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/switch_text_artist" />
    <!-- 野菜について -->
    <CheckBox
        android:id="@id/profile_vegetable"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/switch_text_vegetable" />
</LinearLayout>

次に、resのlayout-v14に上記ファイルと同じ名前でSwitchで定義したXMLを記述します。
widget_profile_onoff.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <!-- アーティストについて -->
    <Switch
        android:id="@id/profile_artist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/switch_text_artist"
        android:textOff="@string/switch_text_off"
        android:textOn="@string/switch_text_on" />
    <!-- 野菜について -->
    <Switch
        android:id="@id/profile_vegetable"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/switch_text_vegetable"
        android:textOff="@string/switch_text_off"
        android:textOn="@string/switch_text_on" />
</LinearLayout>
あとは表示したいレイアウトにincludeします。
<LinearLayout 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"
    android:orientation="vertical" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/profile" />
    <include layout="@layout/widget_settings_onoff" />
</LinearLayout>
※ちなみにidはresのvaluesで以下のように定義しています。
ids.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <item name="profile_artist" type="id"/>
    <item name="profile_vegetable" type="id"/>
</resources>
こうすることで、ICSより前ではCheckboxが表示され、ICS以降ではSwitchが表示されます。 また、チェックのON/OFFのイベントを扱いたい場合は、CompoundButtonを型として使うことでソースコードに修正を加えずにCheckboxとSwitchの処理を扱うことができます。
    private void setupViews() {

        // アーティストについて
        final CompoundButton artistProfile = (CompoundButton) findViewById(R.id.profile_artist);
        artistProfile.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
                // チェック状態を表示
                Toast.makeText(MainActivity.this, buttonView.getText() + ":" + String.valueOf(isChecked), Toast.LENGTH_LONG).show();
            }
        });

        // 野菜について
        final CompoundButton vegetableProfile = (CompoundButton) findViewById(R.id.profile_vegetable);
        vegetableProfile.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
                // チェック状態を表示
                Toast.makeText(MainActivity.this, buttonView.getText() + ":" + String.valueOf(isChecked), Toast.LENGTH_LONG).show();
            }
        });
    }
以下のようにバージョンに応じてCheckboxとSwitchが表示されます。