SQLの窓

2016年08月01日


Android : TabHost のタブに下から上へのアニメーションを設定して、include で同一画面を使用するので 回転しないように AndroidMainfest で設定する

TabHost のタブの切り替わりがあまりにもそっけないので、slide_from_bottom.xml と slide_up.xml を作成して、下から上へと移動するアニメーションを設定しました。左右にしてもいいのですが、それだともう二種類のアニメーションが必要になりそうなので下から上にしました。

Interpolators の値(Android developer)
※ 参考にした記事

TabHost 内の各 TabSpec 内にある TextView の 端末回転時における保存と復帰 では、tab 毎に違った画面を定義しましたが、同じ画面を使用して工数が減るパターンとしてサンプルを作成しました。

ただ、この場合ですと、端末の回転による Activity の再作成で、Tab 内の EditText の保存と復帰が正しくされないので、AndroidMainfest で『回転しない』ように縦固定にしました。
public class MainActivity extends AppCompatActivity {

	private TabHost tabhost;
	private View pview;
	private View tabView1;
	private View tabView2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		// TabHost のインスタンスを取得
		tabhost = (TabHost)MainActivity.this.findViewById(R.id.tabHost);
		// タブ追加の前に必要な初期処理
		tabhost.setup();

		// タブ用のインスタンスを作成
		TabHost.TabSpec tab1 = tabhost.newTabSpec("tab1");
		// タイトル文字列を設定
		tab1.setIndicator("タブ1の\nタイトル");
		// このタブ内に表示するコンテンツを TabHost 画面内の FrameLayout
		// の中にあるうちのコンテンツのひとつを設定
		tab1.setContent(R.id.linearLayout1);
		// TabHost に このタブを追加
		tabhost.addTab(tab1);

		TabHost.TabSpec tab2 = tabhost.newTabSpec("tab2");
		tab2.setIndicator("タブ2の\nタイトル");
		tab2.setContent(R.id.linearLayout2);
		tabhost.addTab(tab2);

		TabHost.TabSpec tab3 = tabhost.newTabSpec("tab3");
		tab3.setIndicator("タブ3の\nタイトル");
		tab3.setContent(R.id.linearLayout3);
		tabhost.addTab(tab3);

		pview = tabhost.getCurrentView();

		tabhost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
			@Override
			public void onTabChanged(String tabId) {
				View currentView = tabhost.getCurrentView();
				int tab = tabhost.getCurrentTab();

				Animation a_out = AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_up);
				Animation a_in = AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_from_bottom);

				pview.setAnimation(a_out);
				currentView.setAnimation(a_in);

				pview = currentView;
			}
		});

		// tab1 内のボタン
		tabView1 = MainActivity.this.findViewById(R.id.linearLayout1);
		Button button1;
		button1 = (Button) tabView1.findViewById(R.id.button);
		button1.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				TextView tv;
				// 画面最上部の TextView
				tv = (TextView) MainActivity.this.findViewById(R.id.textView);

				// 最初のタブの EditText
				EditText editText = (EditText) tabView1.findViewById(R.id.editText);
				tv.setText(editText.getText().toString());

				// tab1 のコンテンツを取得
				tv = (TextView) tabView1.findViewById(R.id.textView2);
				tv.setText(editText.getText().toString());

			}
		});

		// tab2 内のボタン
		tabView2 = MainActivity.this.findViewById(R.id.linearLayout2);
		Button button2;
		button2 = (Button) tabView2.findViewById(R.id.button);
		button2.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				TextView tv;

				// 真ん中のタブの EditText
				EditText editText = (EditText) tabView2.findViewById(R.id.editText);

				// tab2 のコンテンツを取得
				tv = (TextView) tabView2.findViewById(R.id.textView2);
				tv.setText(editText.getText().toString());

			}
		});

	}

}


画面定義
<?xml version="1.0" encoding="utf-8"?>
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="lightbox.july.tabhostapplication.MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:textSize="30dp"/>

    <TabHost
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/tabHost"
        android:layout_below="@+id/textView">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TabWidget
                android:id="@android:id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
            </TabWidget>

            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <include
                    android:id="@+id/linearLayout1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    layout="@layout/tab_entry"/>

                <include
                    android:id="@+id/linearLayout2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    layout="@layout/tab_entry"/>

                <include
                    android:id="@+id/linearLayout3"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    layout="@layout/tab_entry"/>

            </FrameLayout>
        </LinearLayout>
    </TabHost>
</RelativeLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/textView2"
        android:textSize="40dp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="入力を表示"
        android:id="@+id/button"/>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText"/>

</LinearLayout>

※ 便宜的に二つの画面をまとめて表示しています

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest package="lightbox.july.tabhostapplication"
          xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>


アニメーション
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator">
    <translate android:fromYDelta="50%p" android:toYDelta="0" android:duration="160"/>
    <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="160" />

</set>

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromYDelta="0" android:toYDelta="-50%p" android:duration="@android:integer/config_mediumAnimTime"/>
    <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
</set>
※ 便宜上ひとつにして表示しています
※ 上が、slide_from_bottom.xml です


posted by lightbox at 2016-08-01 20:22 | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

Android : TabHost 内の各 TabSpec 内にある TextView の 端末回転時における保存と復帰

TabHost そのものは、ひとつの Activity で処理する場合とても簡単ですが、Android Studio の デザインで各タブの画面を確認できるように、xml で3つの画面定義をして activity_main.xml で include で読み込んでいます。

include タグにはそれぞれ id を設定して、TabSpec のコンテンツとして渡せるようにもしてあります。

端末回転時の保存と復帰に関しても、一般的な onSaveInstanceState と onRestoreInstanceState を使用していますが、画面内のコンテンツの id のパターンを以下のようにして、サンプルコードを作成しています。

1) EditText と Button には全て違った id を設定する
2) TextView には同じ id を設定する

通常、EditText は内部で自動的に内容が保存されて復帰されますが、3つの inclide 内の id を同じにしてしまうと( つまり、ひとつの画面定義で3つの include を使いまわししてしまうと )、保存と復帰がうまくいかないようなので、3つの画面を作成して、別々の id を設定しています。

しかし、同じ id を持った画面を使いまわす事も想定して、TextView には同じ id を設定して、include の id でまず view を取得して、その中の TextView として取得するサンプルコードです。


ここでは、使用していませんが最近の Drawable の取得方法として
Drawable drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.□□□, null);

そして、Tab にアイコンを表示させる方法について
Icon in Tab is not showing up (StackOverflow)
※ 要するにカスタムなインジケータを作成するそうです
public class MainActivity extends AppCompatActivity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		// TabHost のインスタンスを取得
		TabHost tabhost = (TabHost)MainActivity.this.findViewById(R.id.tabHost);
		// タブ追加の前に必要な初期処理
		tabhost.setup();

		// タブ用のインスタンスを作成
		TabHost.TabSpec tab1 = tabhost.newTabSpec("tab1");
		// タイトル文字列を設定
		tab1.setIndicator("タブ1の\nタイトル");
		// このタブ内に表示するコンテンツを TabHost 画面内の FrameLayout
		// の中にあるうちのコンテンツのひとつを設定
		tab1.setContent(R.id.linearLayout1);
		// TabHost に このタブを追加
		tabhost.addTab(tab1);

		TabHost.TabSpec tab2 = tabhost.newTabSpec("tab2");
		tab2.setIndicator("タブ2の\nタイトル");
		tab2.setContent(R.id.linearLayout2);
		tabhost.addTab(tab2);

		TabHost.TabSpec tab3 = tabhost.newTabSpec("tab3");
		tab3.setIndicator("タブ3の\nタイトル");
		tab3.setContent(R.id.linearLayout3);
		tabhost.addTab(tab3);

		// tab1 内のボタン
		Button button1;
		button1 = (Button) MainActivity.this.findViewById(R.id.button);
		button1.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				TextView tv;
				// 画面最上部の TextView
				tv = (TextView) MainActivity.this.findViewById(R.id.textView);

				// 最初のタブの EditText
				EditText editText = (EditText) MainActivity.this.findViewById(R.id.editText);
				tv.setText(editText.getText().toString());

				// tab1 のコンテンツを取得
				View tab1 = MainActivity.this.findViewById(R.id.linearLayout1);
				tv = (TextView) tab1.findViewById(R.id.textView2);
				tv.setText(editText.getText().toString());

			}
		});

		// tab2 内のボタン
		Button button2;
		button2 = (Button) MainActivity.this.findViewById(R.id.button2);
		button2.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				TextView tv;

				// 真ん中のタブの EditText
				EditText editText = (EditText) MainActivity.this.findViewById(R.id.editText2);

				// tab2 のコンテンツを取得
				View tab2 = MainActivity.this.findViewById(R.id.linearLayout2);
				tv = (TextView) tab2.findViewById(R.id.textView2);
				tv.setText(editText.getText().toString());

			}
		});


	}

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

		TabHost tabhost = (TabHost)findViewById(R.id.tabHost);

		// タブ位置の復帰
		int currentTab =  savedInstanceState.getInt("CurrentTab");
		if ( currentTab != 0l ) {
			tabhost.setCurrentTab(currentTab);
		}
		else {
			tabhost.setCurrentTab(0);
		}

		// 一番上の TextView を復帰
		String textTop = savedInstanceState.getString("TextViewTop");
		if (textTop != null ) {
			TextView tv;
			tv = (TextView) MainActivity.this.findViewById(R.id.textView);
			tv.setText(textTop);
		}

		// tab1 内の TextView を復帰
		String text1 = savedInstanceState.getString("TextView1");
		if (text1 != null ) {
			View tab1 = MainActivity.this.findViewById(R.id.linearLayout1);
			TextView tv = (TextView) tab1.findViewById(R.id.textView2);
			tv.setText(text1);
		}

		// tab2 内の TextView を復帰
		String text2 = savedInstanceState.getString("TextView2");
		if (text2 != null ) {
			View tab2 = MainActivity.this.findViewById(R.id.linearLayout2);
			TextView tv = (TextView) tab2.findViewById(R.id.textView2);
			tv.setText(text2);
		}

	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);

		// タブ位置の保存
		TabHost tabhost = (TabHost)MainActivity.this.findViewById(R.id.tabHost);
		int currentTab = tabhost.getCurrentTab();
		outState.putInt("CurrentTab", currentTab);

		// 一番上の TextView を保存
		TextView tvTop = (TextView) MainActivity.this.findViewById(R.id.textView);
		outState.putString("TextViewTop", tvTop.getText().toString());

		// tab1 のコンテンツを取得
		View tab1 = MainActivity.this.findViewById(R.id.linearLayout1);
		TextView tv1 = (TextView) tab1.findViewById(R.id.textView2);
		outState.putString("TextView1", tv1.getText().toString());

		// tab2 のコンテンツを取得
		View tab2 = MainActivity.this.findViewById(R.id.linearLayout2);
		TextView tv2 = (TextView) tab2.findViewById(R.id.textView2);
		outState.putString("TextView2", tv2.getText().toString());

	}
}


画面定義
<?xml version="1.0" encoding="utf-8"?>
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="lightbox.july.tabhostapplication.MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:textSize="30dp"/>

    <TabHost
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/tabHost"
        android:layout_below="@+id/textView">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TabWidget
                android:id="@android:id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
            </TabWidget>

            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <include
                    android:id="@+id/linearLayout1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    layout="@layout/tab_entry"/>

                <include
                    android:id="@+id/linearLayout2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    layout="@layout/tab_entry2"/>

                <include
                    android:id="@+id/linearLayout3"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    layout="@layout/tab_entry3"/>

            </FrameLayout>
        </LinearLayout>
    </TabHost>
</RelativeLayout>


3つの tab 毎の定義
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/textView2"
        android:textSize="40dp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="入力を表示"
        android:id="@+id/button"/>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText"/>

</LinearLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/textView2"
        android:textSize="40dp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="入力を表示"
        android:id="@+id/button2"/>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText2"/>

</LinearLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/textView2"
        android:textSize="40dp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="なにもしない"
        android:id="@+id/button3"/>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText3"/>

</LinearLayout>
※ 便宜上3つにまとめていますが、xml ファイルはそれぞれ 作成しています



posted by lightbox at 2016-08-01 13:40 | Android Studio 2 | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり