ViewHolder

前回のように、文字列などデータをセットするViewの参照をあらかじめ保持しておきたい場合で、1アイテムに複数のビューの場合は、ViewHolderを使う。

【Android】ViewHolderパターンの使い方|IT小人の前進

ViewHolderというクラスが定義されてるわけじゃなくて、自分で作成する。

今回は2つのTextView。
ViewHolder.javaは、

2つのTextView。
ListItem.javaは、

こっちはどちらもString。
CustomAdapter.javaは、

viewHolderの持つ2つのTextViewに、convertView.findViewByIdで探した2つのTextViewをそれぞれ渡しておいてviewHolderをsetTag。
nullでなければ、getTagでviewHolderを取得できる。
MainActivity.javaは、

1万個用意。

起動時
起動時

起動時。

どうだろう。動かしてもわからん。
どうだろう。動かしてもわからん。

どうだろう。動かしてもわからん。
まあ、ViewHolderは、この後にも繋がる話なので。

Sample/android/patternViewHolder/patternViewHolder/src/patternViewHolder at master · bg1bgst333/Sample · GitHub

View.getTag

View.getTagで、ビューにセットしておいたタグを取得する。

View  |  Android Developers

今回はListViewの中で使う。
list_item.xmlで、

LinearLayoutの中にTextViewというアイテム。
activity_main.xmlは、

ListView。
CustomAdapter.javaで、

package com.bgstation0.android.sample.view_;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

// カスタムアダプタ
public class CustomAdapter extends ArrayAdapter<String> {

	// メンバフィールドの定義.
	private final LayoutInflater mInflater;	// インフレータmInflater.
	
	// コンストラクタ.
	public CustomAdapter(Context context, int textViewResourceId, List<String> objects) {
		super(context, textViewResourceId, objects);
		// TODO Auto-generated constructor stub
		mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);	// mInflaterを生成.
	}

	// アイテム表示のカスタマイズ
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// convertViewがnullの時.
		if ( == null){
			convertView = mInflater.inflate(R.layout.list_item, null);	// convertViewがnullならinflater.inflateで取得.(ここは難しいのでひとまずこういうものだと捉えておく.)
		}
		TextView liTextView = (TextView)convertView.findViewById(R.id.list_item_textview);	// convertView.findViewByIdでR.id.list_item_textviewをliTextViewに格納.
		liTextView.setText(getItem(position));	// position番目のアイテムをliTextView.setTextでセット.
		return convertView;	// convertViewを返す.
	}
	
}

引数のconvertViewがnullの時は再生成が必要なので、mInflater.inflateの結果のViewをconvertViewに格納。
convertView.findViewByIdでliTextViewを探してそれに現在位置のテキストをセット。

アイテム1万個用意。

起動時
起動時

起動時。
動かしてみる。

どうだろうか。もっさりするかはわからない。
どうだろうか。もっさりするかはわからない。

どうだろうか。もっさりするかはわからない。
要はアイテムが多すぎると、convertView.findViewByIdは時間かかるので、パフォーマンスに影響が出るかもということ。

convertViewがnullなら、再生成が必要なので、mInflater.inflateとconvertView.findViewByIdしないといけない。
で、それが終わったら、convertView.setTagでliTextViewをタグとしてセットする。
nullでなければ、再生成不要だから、convertView.getTagでliTextViewを取得できるし、それにテキストをセットするだけでいい。
convertViewがいれば、liTextViewもいるわけだから、liTextViewの参照を取得出来れば、わざわざfindViewByIdする必要もない。

どうだろうか
どうだろうか

どうだろうか。
動かしてみる。

わからない
わからない

わからない。
でもアイテムがもっと大量にあった場合のパフォーマンスには影響しそう。

Sample/android/View/getTag/src/View at master · bg1bgst333/Sample · GitHub

View.setTag

View.setTagで、ビューにタグをセットできる。

View  |  Android Developers

いろいろな使い方があるが、今回はボタンに文字列としてのタグを付けて、クリック時にどちらが押されたかを判定する。
strings.xmlで、

このようにして、activity_main.xmlで、

Buttonを2つ用意。
MainActivity.javaは、

button1にTAG_BUTTON_1("tag_button_1")、button2にTAG_BUTTON_2("tag_button_2")をView.setTagで付けて、onClick時にView.getTagで取得したタグが、どちらなのか判定してる。

起動時
起動時

起動時。
Button1を押すと、

こう出るので、TAG_BUTTON_1が取得出来てる。
こう出るので、TAG_BUTTON_1が取得出来てる。

こう出るので、TAG_BUTTON_1が取得出来てる。
Button2を押した時も、

こう出るので、TAG_BUTTON_2が取得出来てる
こう出るので、TAG_BUTTON_2が取得出来てる

こう出るので、TAG_BUTTON_2が取得出来てる。

Sample/android/View/setTag/src/View at master · bg1bgst333/Sample · GitHub

CollapsingToolbarLayout

スクロールの動きとToolbarの表示の連動の仕方にはいろいろある。
前回のように、activity_main.xmlで、

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Toolbar
            android:id="@+id/toolbar1"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <TextView
            android:id="@+id/textview_longtext"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/textview_longtext_text" />

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

AppBarLayoutでapp:layout_scrollFlags="scroll|enterAlways"の場合は、

1番下まで行って
1番下まで行って

1番下まで行って、上に戻ろうとすると、

すぐToolbarが出てくる
すぐToolbarが出てくる

すぐToolbarが出てくる。
どんな位置からでも上に戻ろうとしたときにToolbarが連動して出てくる。

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Toolbar
            android:id="@+id/toolbar1"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlwaysCollapsed" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <TextView
            android:id="@+id/textview_longtext"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/textview_longtext_text" />

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

しかし、app:layout_scrollFlags="scroll|enterAlwaysCollapsed"にすると、

下まで行って
下まで行って

下まで行って、上に戻っても、

出てこない
出てこない

出てこない。

リストの1番上のところまで戻って初めて出てくる
リストの1番上のところまで戻って初めて出てくる

リストの1番上のところまで戻って初めて出てくる。
スクロールにはもうひとつ、

app:layout_scrollFlags="scroll|exitUntilCollapsed"

というフラグがあるが、これはCollapsingToolbarLayoutで使う。

CollapsingToolbarLayout  |  Android Developers
Androidのマテリアルデザイン ~スクロール連動~ (2/3):CodeZine(コードジン)

これらを使うと、Toolbarを伸縮しつつ、一定のところで止める事ができる。

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar1"
        android:layout_width="match_parent"
        android:layout_height="200dp" >

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed" >

            <Toolbar
                android:id="@+id/toolbar1"
                android:layout_width="match_parent"
                android:layout_height="?android:attr/actionBarSize"
                android:background="@color/colorPrimary"
                app:layout_collapseMode="pin" />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <TextView
            android:id="@+id/textview_longtext"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/textview_longtext_text" />

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

AppBarLayoutで200dpにすることで、最初の高さは200dpになる。
CollapsingToolbarLayoutを中に入れて、そちらにapp:layout_scrollFlags="scroll|exitUntilCollapsed"を指定。
Toolbarでapp:layout_collapseMode="pin"を指定。
一番小さくなった時の高さは、android:layout_height="?android:attr/actionBarSize"に基づくから、Toolbarのデフォルトの高さのはず。

最初は200dpだからこれぐらい大きくなる
最初は200dpだからこれぐらい大きくなる

最初は200dpだからこれぐらい大きくなる。

下に行くとどんどん小さくなる
下に行くとどんどん小さくなる

下に行くとどんどん小さくなる。

あれ?止まらない・・・。
あれ?止まらない・・・。

あれ?止まらない・・・。

消えてしまった・・・。
消えてしまった・・・。

消えてしまった・・・。
本当ならToolbarの高さより小さくはならないようにどこも書いてあるのだが・・・。

いろいろなCoordinatorLayoutパターン - Qiita

上記の記事などいろいろ見たけど、

android:minHeight="?android:attr/actionBarSize"を付けたら、

ここから
ここから

ここから、

小さくなって
小さくなって

小さくなって、

ここからは小さくならなくなった
ここからは小さくならなくなった

ここからは小さくならなくなった。
でも、付けてない記事もあるので何が違うのだろうか・・・。

Sample/android/CollapsingToolbarLayout/CollapsingToolbarLayout/CollapsingToolbarLayout_ at master · bg1bgst333/Sample · GitHub

NestedScrollView

NestedScrollViewを使うと、スクロールの動きとToolbarの表示が連動する。

NestedScrollView  |  Android Developers
Androidのマテリアルデザイン ~スクロール連動~ (2/3):CodeZine(コードジン)

strings.xmlで、

textview_longtext_textはスクロール効くようにたくさんの改行と文字で長くしている。
activity_main.xmlで、

ポイントはToolbarの、

app:layout_scrollFlags="scroll|enterAlways"

とNestedScrollViewの、

app:layout_behavior="@string/appbar_scrolling_view_behavior"

でenterAlwaysで上に戻すとToolbarも現れだす。
appbar_scrolling_view_behaviorは自分で定義するのではなく、こういうものが既に定義されているのでそのまま使う。

最初はこう
最初はこう

最初はこう。
下に下がっていくと、

Toolbarが隠れ始める
Toolbarが隠れ始める

Toolbarが隠れ始める。

完全に隠れた
完全に隠れた

完全に隠れた。

Sample/android/NestedScrollView/NestedScrollView/NestedScrollView_ at master · bg1bgst333/Sample · GitHub

AppBarLayout

AppBarLayoutは、アクションバーの構成を決めるレイアウトで、この中にToolbar以外のモノも入れることで、Toolbarの下になんらかのViewを配置できる。

AppBarLayout  |  Android Developers
Androidのマテリアルデザイン ~スクロール連動~ (1/3):CodeZine(コードジン)

まず、app/build.gradleで、

Android Design Support Libraryを追加。
styles.xmlで、

"AppTheme"は"android:Theme.Material.NoActionBar"をベースに。
strings.xmlは、

こうする。

mipmap-xhdpiにlogo1を配置
mipmap-xhdpiにlogo1を配置

mipmap-xhdpiにlogo1を配置。
activity_main.xmlは、

AppBarLayoutの中に、ToolbarとButton。
縦のLinearLayoutみたいになる。
MainActivity.javaは、

toolbar1のセットと一応Buttonも押したらToast。

こんな風になる
こんな風になる

こんな風になる。
BUTTON1を押すと、

Toastも出る
Toastも出る

Toastも出る。

Sample/android/AppBarLayout/AppBarLayout/AppBarLayout_ at master · bg1bgst333/Sample · GitHub

Toolbar.setSubtitleTextColor

Toolbar.setSubtitleTextColorで、サブタイトルのテキストの色をセットする。

Toolbar  |  Android Developers

MainActivity.javaで、

Color.GRAY(濃灰色)をセット。

濃灰色になった
濃灰色になった

濃灰色になった。

Sample/android/Toolbar/setSubtitleTextColor/Toolbar_ at master · bg1bgst333/Sample · GitHub