15

メニューの種類

コンテキスト メニューとポップアップ メニューの違いを概説することから始めましょう (ここから取得)。

  • PopupMenu は、Viewに固定されたモーダル メニューです。

  • コンテキスト メニュー [特にフローティング コンテキスト メニューについて話している] は、UI の特定の項目またはコンテキスト フレームに影響を与えるアクションを提供します。任意のビューにコンテキスト メニューを提供できますが、ほとんどの場合、ListView、GridView、またはユーザーが各項目に対して直接操作を実行できるその他のビュー コレクション内の項目に使用されます。

ガイダンスとして、ドキュメントでは用途を区別しています: - PopupMenu: "特定のコンテンツ (Gmail のメール ヘッダーなど)に関連するアクションにオーバーフロー スタイルのメニューを提供する..." - ContextualMenu: "選択したコンテンツに影響するアクションの場合... "

私はPopupMenuの視覚的な外観と相互作用を求めています。

私のセットアップ(および目標)

各項目の右側にボタンがある ListView があります。

--------------------
| Item 1        [ ]|
--------------------
--------------------
| Item ...      [ ]|
--------------------
--------------------
| Item n        [ ]|
--------------------

各 ListItemを保持しながらonItemClick、ボタンを活用して をトリガーしたいと思いますPopupMenu

のアクションは にPopupMenuリストされているmy_menu.xmlため、メニューの各インスタンスの唯一の違いは、クリックされた項目です。

私が試したこと

この投稿に従って、 for each ボタンを追加するためにオーバーライドを試みましgetView()た。結果は矛盾していました。すべてのクリックが登録されたわけではありません (おそらくリサイクルが原因です - 私はまだこの修正を試していません)。ListAdapterOnClickListener

また、リスト項目が長押しされたときにのみトリガーされることを除いて、非常に簡単なコンテキスト メニューを追加しようとしました。

getView()メソッドは進むべき道ですか、それとももっと簡単なものがありますか?

私のリストビューには、Play Music のプレイリストの各トラックと同様に、アイテムごとにミニ オーバーフロー ボタンがあります。オーバーフロー ボタンをクリックすると、各アイテムの PopupMenu が表示されます。長押しは何もしません。

私はそれが欲しいのですが、方法がわかりませんか?メニュー ページでは、個々のビューのポップアップ メニューを有効にする方法についてのみ詳しく説明しています。

registerForContextMenu(ListView lv)ListView全体に適用できるのは私が見た唯一のものですが、それはリスト全体の長押しでのみ機能するようです。そのイベントをリスト項目の特定のビューのクリックにフックする方法はありますか (リスト項目の残りのリスト項目のクリックを維持しながら)?

onClickListenerここで説明されているようにを設定しようとしましgetView()たが、PopupMenu がぎこちなく感じられ、すべてのクリックが毎回登録されるわけではありません (常に一貫性がありませんでした)。

更新 - getView() を再度オーバーライドして

StacksCursorAdapter を作成するときに、フィールドとして格納されている StackViewFragment のインスタンスを渡します (これにより、クリック リスナーとしてビューに割り当てることができます)。

ViewHolderのクラスですpublic final ImageView miniOverflow

StacksCursorAdapter (SimpleCursorAdapter を拡張):

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row = super.getView(position, convertView, parent);
    ViewHolder holder = (ViewHolder) row.getTag();

    if (holder == null) {
        holder = new ViewHolder(row);
        row.setTag(holder);
    }
    holder.miniOverflow.setTag(R.id.tag_stack_position, position);
    holder.miniOverflow.setOnClickListener(listener);

    return row;
}

StackViewFragment (ListFragment を拡張し、View.OnClickListener を実装):

@Override
public void onClick(View v) {
    Log.d(TAG, "mini overflow clicked");
    Log.d(TAG, "position:::::" + v.getTag(R.id.tag_stack_position));

    PopupMenu popup = new PopupMenu(getActivity(), v);
    MenuInflater inflater = popup.getMenuInflater();
    inflater.inflate(R.menu.menu_stackview_listitem, popup.getMenu());
    popup.show();
}

stack_list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<!-- a single row item for a Stacks listview -->
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:descendantFocusability="blocksDescendants"
        >

    ...
    <other views>
    ...


    <ImageView
            android:id="@+id/moreoverflow_btn"
            android:focusable="false"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:alpha="0.4"
            android:scaleType="fitCenter"
            android:src="@drawable/ic_menu_moreoverflow_black"
            android:layout_alignParentRight="true"
            />
</RelativeLayout>

このジャンクションでの問題は、(ボタン上で) 登録するためのクリックを取得するために、ときどき数回クリックする必要があることです。これはスクロールしないため、ビューのリサイクルとは関係ありません。

結論(正しいとマークされたeskimoapps.comによる解決策)

したがって、タッチ ターゲットが期待していた場所にないことを除いて、複数のクリックに問題はありませんでした。ミニ オーバーフローに使用していた画像アセットは右に重み付けされています (3 つの点が画像の右端近くにあるように)。タッチ ターゲット) は、半分の時間 (facepalm)を見逃していたことを意味します。

getView()上で示したオーバーライドは問題なく機能しているようで、実際にgetView()は、必要な場合にのみ OnClickListener を設定することでさらに変更できます (ただし、タグの更新は、新しく作成されたビューだけでなく、すべてのビューに対して行う必要があります)。 :

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row = super.getView(position, convertView, parent);
    ViewHolder holder = (ViewHolder) row.getTag();

    if (holder == null) {
        holder = new ViewHolder(row);
        row.setTag(holder);
        holder.miniOverflow.setOnClickListener(listener);
    }
    holder.miniOverflow.setTag(R.id.tag_stack_position, position);

    return row;
}
4

2 に答える 2

3

getView をオーバーライドすることは正しいアプローチであり、ビューをリサイクルすると事態が複雑になると考えるのは正しい方向に進んでいます (実際にビューをリサイクルしている場合)。

getOnClickListener メソッドがないため、リサイクルされたビューと膨張していないビューに新しい OnClickListener を設定する必要があります (getOnClickListener を実装するカスタム ビューを作成したくない場合)。

于 2013-06-30T21:40:53.330 に答える
1

今日これを行いたい場合は、HolderViewパターンを使用します。

HolderView パターンには、カスタム ビュー/ビューグループ (リスト/グリッド アイテム レイアウトのルートであるビュー/ビューグループを 3 つの標準ビュー コンストラクターで拡張するクラス) が必要です。

一般的な考え方は、アダプターはビューのコンテンツを直接更新する責任を負わないということです。代わりに、それ自体を更新するために必要なすべての情報をビューに提供します。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = createView(parent);
    }

    updateView((GalleryItemView) convertView, position);

    return convertView;
}

private View createView(ViewGroup parent) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());

    return inflater.inflate(R.layout.gallery_item_view, null, false);
}

private void updateView(GalleryItemView view, int position) {
    GalleryElement item = getItem(position);

    view.updateWith(position, item, listener);
}

私からしてみれば:

public class GalleryItemView extends ImageView {

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

    void updateWith(int position, final GalleryElement item, final GalleryAdapter.GalleryItemListener listener) {
        if (position % 2 == 0) {
            setBackgroundColor(getColor(android.R.color.holo_orange_dark));
        } else {
            setBackgroundColor(getColor(android.R.color.holo_orange_light));
        }

        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                listener.onGalleryItemClicked(item.id);
            }
        });
    }

    @ColorInt
    private int getColor(@ColorRes int colorRes) {
        return getResources().getColor(colorRes);
    }

}
于 2013-12-23T09:04:52.857 に答える