4

iPhoneの連絡先アプリでiPhoneに似たスライドヘッダー(開始文字で連絡先をグループ化するスライドヘッダー)のような同様の効果を実装しようとしています。

これは私のアプリの画面であり、達成したいのは次のとおりです。

ここに画像の説明を入力

リストをソートするための「ガイド ヘッダー」と 3 つの「タブ」があります。ユーザーがリストを上にスクロールすると、すべて (ガイド ヘッダー、タブ、リスト) が上にスクロールされるようにします。ただし、タブが画面の上部に到達すると (ガイド ヘッダーが画面から消えるだけです)、タブを停止してそこにとどまり (「スティッキー ヘッダー」として残ります)、リスト項目のみが次のようにスクロールします。通常のリスト ビューで。

リスト ビューの上にビュー グループ (ガイド ヘッダー) があります。

まず、リスト ビューのスクロール位置に応じて、ガイド ヘッダーの位置を調整したいと考えています。

最初のアプローチ: 私の考えは、onScrollListener をリスト ビューに設定し、ガイド ヘッダーの上マージンをリスト ビューの最初の項目のスクロール位置 (負の値) に変更することでした。

ロジックは正しいですが、私が直面している問題は、リスト ビューをスクロールしているときに、ガイド ヘッダー ビューが十分に速く再描画されないことです。ガイド ヘッダー ビューは、リスト ビュー フリングが終了したときにのみ更新されます (変更されたトップ マージン値に)。ゆっくりスクロールしてもダメ。ガイド ヘッダー ビューまたはその親を無効化 (invalidate()) しても、無効化要求がキューに入れられるだけなので役に立ちませんが、無効化と再描画はすぐには行われず、UI スレッドがアイドル状態になったときにのみ行われます。 、ユーザーがまだスクロールリストビューに指を置いている間は発生しないようです。リストビューを飛ばすと、UIスレッド全体がブロックされるか、それ自体がビジー状態になるようです。

したがって、主な問題は、ユーザーがリスト ビューをスクロールしている間、ガイド ヘッダー ビューの余白を変更してもすぐには表示されないことです。私がこれを使用しているコード:

@Override
public void onScroll(final AbsListView view, final int firstVisibleItem,
    final int visibleItemCount, final int totalItemCount) {

    // Get the first list item and check it's scroll position. This will be the value (top), that we also
    // use the scroll the header parallel.
    View v = mainList.getChildAt(0);
    final int top = (v==null)?0:v.getTop();

    // This logs the current scroll position of the first list item element/view group.
    Log.d("onScroll", "onScroll: " + top);

    // Here we finally change the margin (setting a negative margin) to the header element.
    ((LinearLayout.LayoutParams)(findViewById(R.id.header_container).getLayoutParams())).setMargins(0, top, 0, 0);

    // was just a test: invalidating the outer container/view group, doesn't help
    // findViewById(R.id.ll_container).invalidate();  
}

上記のコードに挿入した "onScroll:" ログ出力が logcat に表示されますが、次の上部マージンの調整が表示されません。

私の 2 番目のアプローチ:ガイド ヘッダー + タブにスクロールビューを使用し、それらを操作することです。リスト ビューの onScroll メソッドから scrollView.scrollTo(0,Math.abs(Math.abs(top)) を使用してコードからガイド ヘッダー (スクロール ビュー) をスクロールすると、ほとんどすぐに画面に表示されます。ただし、ユーザーがリスト ビューを非常に速く動かした場合は、あまり正確ではなく、安定していません。つまり、間隔を空けてジャンプし、滑らかに見えません。正確で安定しているのは、ゆっくりとスクロールした場合のみです。

私の質問は次のとおりです。このようなスライド ヘッダー効果を達成するためのベスト プラクティスはありますか。より具体的には、ユーザーがまだリスト ビューをスクロールしている間にガイド ヘッダー ビューを強制的に再描画する方法はありますか (私の最初に言及したアプローチで) )。

4

2 に答える 2

2

これには、いくつかのトリックを使用する必要があります(そのような機能のすぐに使用できる実装はありません)。
たとえば、ビューでジェスチャを検出できます。

  • 現在のジェスチャが下へのスクロールに一致し、最初のリスト項目が表示されている場合、ヘッダーのサイズを 0 にアニメート縮小し、タブ ビューのサイズを match_parent に縮小します。ヘッダーがもう存在しない場合にのみ、リストのスクロールを開始します。
  • 現在のジェスチャがスクロール アップに一致し、最初のジェスチャがすでに表示されている場合は、ヘッダーをアニメーション化して元のサイズに拡張します。

したがって、ヘッダー ビューでアニメーションを使用することが解決策になる場合があります。

更新
他の回避策は、List(アダプターの値配列) を拡張することです:
ヘッダー表現の上部に新しい (ダミー) アイテムを挿入し、メソッドを変更しますListAdaptergetView

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    if (position == 0)
    {
        convertView = inflater.inflate(R.layout.sliding_header, parent, 
            false);
        return convertView;
    }
    //TODO: your original method body comes here
}

によって参照される xml にR.layout.sliding_headerは、リストのヘッダー レイアウトが含まれている必要があります。

にカスタムOnScrollListener実装を適用するとListView、スクロールバーが非表示になるため、ヘッダーが実際にはリストの項目であることがわかりません。
このリスナーをlistViewアクティビティのonCreateメソッドに追加する必要があります。

listView.setOnScrollListener(new MyScrollListener());

どこにMyScrollListenerある:

/**
 * Custom OnScrollListener
 */
private final class MyScrollListener implements OnScrollListener
{
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState)
    {}

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, 
            int visibleItemCount, int totalItemCount)
    {
        if (view.getFirstVisiblePosition() == 0)
            view.setVerticalScrollBarEnabled(false);
        else if (!view.isVerticalScrollBarEnabled())
            view.setVerticalScrollBarEnabled(true);
    }
}
于 2011-05-08T13:52:38.987 に答える
0

そのために私の ExpandAnimation を試してみることもできると思います。 http://udnic.wordpress.com/2011/09/03/expanding-listview-items/

「ガイドヘッダー」ビューのアニメーションクラスを渡すだけで、アニメーションに作業を任せることができます。その場合、スクロールは必要なく、スムーズです。

于 2011-09-03T17:38:30.430 に答える