結構昔からあったけど、なんか最近よく見るQuickReturnと言われるUIを試してみました。
QuickReturnって何?というと、画面をスクロールダウンするとボタンが隠れて、スクロールアップするとボタンが表示されたりな画面です。
今のGoogle+がまさにそれ。んでちょっと前のGmailもそれ。
イメージつくでしょうか。

んでQuickReturnの実装方法などは結構多いです。
QuickReturnやScrolling Tricksで検索すると出ると思います。

んで大元
■スクロールビュー(Roman Nurik氏)
■リストビュー(Lars Werkman氏)

どちらもスクロールビューやリストビューに余白用ヘッダーを割り当てて、余白用ヘッダーの上に実際に表示させたいヘッダーを重ねてる感じ。
んであとはスクロールに合わせてTranslateする。フッターも考えは一緒だけどフッターの場合は横幅いっぱいなバータイプじゃなければ、余白用のフッターをいれずにコンテンツに重ねちゃう場合が多いかも。Google+はそうですね。昔はフッター入れてたけど。

スクロールでのY軸、計算はなんとなく人それぞれで若干違う。自分の場合はRoman Nurik氏のScrolling Tricksを元にしてほとんど統一。単純にスクロールが一番上、逆スクロール中、ヘッダー隠れ中の三つのフラグのみでいけるので。

んでリストビューの場合、スクロールビューと同じように表示中のrowのトップを取得できるようにリストビューを改造する。Lars Werkman氏のQuickReturnListViewがまさにそれなのでこれをもとにフォークすればよい。なぜフォークかというとこのまま使ってもaddとかすると内部で持っているオフセットリストの数が更新されないので落ちるから。

QuickReturnListView内のcomputeScrollY()を以下のように変える。

-----------------------------
public void computeScrollY() {
mHeight = 0;
//前回のmItemCountを一旦保持
int c = mItemCount;
mItemCount = getAdapter().getCount();
//新しいmItemCountと比べて差異があればmItemOffsetYを再セット
if (mItemOffsetY == null||c!=mItemCount) {
mItemOffsetY = new int[mItemCount];
}
for (int i = 0; i < mItemCount; ++i) {
View view = getAdapter().getView(i, null, this);
view.measure(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
mItemOffsetY[i] = mHeight;
mHeight += view.getMeasuredHeight();
System.out.println(mHeight);
}
scrollIsComputed = true;
}

-----------------------------

んでとりあえずはよい。

あとは実際の配置だがActivityやFragment内でビュー描画後に初期設定とか(幅などの取得)して、OnScrollListenerをセットしたビューのonScroll内で動かした際の動作を設定する。onScroll内の動きはこんな感じで最後にヘッダーを動かしている。

-----------------------------
    //余白分のView
private View mPlaceHolder;
//実際のヘッダー
private View mQuickReturnView;

private static final int STATE_ONSCREEN = 0;
private static final int STATE_OFFSCREEN = 1;
private static final int STATE_RETURNING = 2;

       //ヘッダーの縦幅
private int mQuickReturnHeight;
private int mState = STATE_ONSCREEN;
private int mMinRawY = 0;
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
int mScrollY = 0;

if (mListView.scrollYIsComputed()) {
mScrollY = mListView.getComputedScrollY();
}

int rawY = mPlaceHolder.getTop() - mScrollY;
int translationY = 0;

switch (mState) {
case STATE_OFFSCREEN:
if (rawY <= mMinRawY) {
mMinRawY = rawY;

if (mQuickReturnView.getTranslationY() < -mQuickReturnHeaderHeight)
return;

} else {
mState = STATE_RETURNING;
}
translationY = rawY;

break;

case STATE_ONSCREEN:
if (rawY < -mQuickReturnHeight) {
mState = STATE_OFFSCREEN;
mMinRawY = rawY;
}
translationY = rawY;
break;

case STATE_RETURNING:
translationY = (rawY - mMinRawY) - mQuickReturnHeight;
if (translationY > 0) {
translationY = 0;
mMinRawY = rawY - mQuickReturnHeight;

if (mQuickReturnView.getTranslationY() == 0)
return;
}

if (rawY > 0) {
mState = STATE_ONSCREEN;
translationY = rawY;
}

if (translationY < -mQuickReturnHeight) {
mState = STATE_OFFSCREEN;
mMinRawY = rawY;
}

break;
}

mQuickReturnView.setTranslationY(translationY);

}

-----------------------------
という具合でやれます。
元と違うのは規定値に達したらreturnするところ。setTranslationの中を見たら現在の軸と変えたい軸が同じなら無視する。なので完全に表示状態ならいいんですが消えてる状態だとTranslationし続けるってことですね。なので消えたらTranslationしなくていいよってreturnしてる感じ。

あとGoogle+のようにActionBar+Drawer的な扱いをするならばDrawer内のpaddingTopにActionBar分の高さを当ててやればいい。
Google+のようにmarginTopで余白かますのもいいけど、個人的には正直いただけないドロワー時にバーを戻して隠してますが、ゆっくりドロワーしてくとぽっこり空白が見えちゃうのはださすぎる。

最後にここまで書いたが結構ごまごまするのでサンプルプロジェクトを用意してますん。

プロジェクト>DefaultQuickReturnActivity、ActionQuickReturnActivity
*ちなみにsetTranslationY()をTranslateAnimationやlayoutメソッドに変えれば、honeycomb以下でも動作はするけどあまりおすすめしない。

TranslateAnimationはダメな子なので動いているように見えるが実際のビューは動いていないのでボタンなどのActionを配置すると消えてるのに押したら動作するんだけどって事になる。layoutメソッドはなんとなくコストがかかりそうな気がしてのう。。スクロールでぐいぐい動かれるたび無理に移動するとつらいんではないかと思っております。一応サンプルのDefaultQuickReturnActivityがhoneycomb以下の場合にTranslateAnimationで動くようしてるます。。