android - 如何将多个触摸操作附加到单个列表项?

标签 android android-layout android-listview onclick android-listfragment

我正在为具有相关评论项目 使用以下列表布局。 评论的数量由右侧的框指示。

Item list layout

目前,我正在使用 onListItemClick 处理程序来启动另一个details View 。

public class CustomListFragment extends ListFragment
                                implements LoaderCallbacks<Cursor> {

    private Activity mActivity;
    private CursorAdapter mAdapter;
    private QueryParameters mQueryParameters;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setEmptyText("No data to display");

        mActivity = getActivity();
        if (mActivity == null)  {
            Log.e(getClass().getName(), "Activity is null");
            return;
        }
        // Prepare query.
        mQueryParameters = QueryHelper.getQueryParameters(mActivity);
        if (mQueryParameters == null || !mQueryParameters.isPreparedForLoader()) {
            Log.d(getClass().getName(), "One or more query parameters are null.");
            return;
        }
        mAdapter = new CustomCursorAdapter(mActivity, null, 0);
        setListAdapter(mAdapter);
        getLoaderManager().initLoader(0, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle extras) {
        return new CursorLoader(mActivity,
                mQueryParameters.uri,
                mQueryParameters.fromColumnsLoader,
                mQueryParameters.selection,
                mQueryParameters.selectionArgs,
                mQueryParameters.sortOrder);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        mAdapter.swapCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        Intent intent = new Intent(mActivity, ItemDetailsActivity.class);
        intent.putExtra("ITEM_URI", mItemUri);
        mActivity.startActivity(intent);
    }
}

我想实现用户可以触摸右侧的框元素。然后,此操作应启动关联的 CommentsActivity。但是,当用户触摸左侧时,它仍应启动 ItemDetailsActivity
在这两种情况下,我都需要传递带有 Intent 的 itemUri,以便特定 details View 或 comments 列表item 可以加载。
ListFragment 使用 CursorAdapterTextView 绑定(bind)到 item 的属性。

问题:

  • 如何将第二个触摸操作附加到单个列表项?

最佳答案

您没有发布任何与适配器本身相关的代码,但我找到了您的 previous question而且你大部分时间都在那里。

快速而肮脏的答案

bindView() 中,让我们修改您的 comments_count TextView 以保存标记中当前行的索引(对于您的 itemUri)并添加一个简单的 OnClickListener:

public void bindView(View view, Context context, Cursor cursor) {
    ViewHolder holder = (ViewHolder)view.getTag();
    if (holder == null) {
        ...
        holder.comments_count.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // Get the position from the ViewHolder
                long id = (Long) v.getTag();
                Toast.makeText(v.getContext(), "Comment Click: " + id, Toast.LENGTH_SHORT).show();
            }
        });
    }
    ...
    holder.comments_count.setTag(cursor.getLong(0));
}

当用户单击该行时,它仍将调用 onListItemClick(),除非他们单击评论框。评论框触发上面的 OnClickListener,您可以在其中将用户定向到您的 CommentsActivity。您没有提到在哪里获取 itemUri 的不同值,但我假设您需要行的 ID 才能获取它。


优秀答案

在您之前的问题中,我注意到您正在进行一些重复调用,并且 Thiago Moreira Rocha 的布局非常复杂,无法重复使用(对于每个 ListView 行。)因此我提出了一种不同的方法。我已将我的答案分为与 comments_count 的适配器、行布局和颜色相关的部分:

适配器
我将完整发布代码,然后在底部进行解释:

public class CustomCursorAdapter extends CursorAdapter {
    private LayoutInflater mInflater;
    private int[] mFrom;

    private OnClickListener commentClick = new OnClickListener() {
        @Override
        public void onClick(View v) {
            // Get the position saved in bindView()
            long id = (Long) v.getTag();
            Toast.makeText(v.getContext(), "Comment Click: " + id, Toast.LENGTH_SHORT).show();
        }
    };

    public CustomCursorAdapter(Context context, Cursor cursor, int flags) {
        super(context, cursor, flags);
        mInflater = LayoutInflater.from(context);
    }

    private void applyColorFilter(Drawable drawable, int count) {
        drawable.clearColorFilter();
        if (count > 0) {
            float saturation = (count * 15) / 100f;
            // The value gets pinned if out of range.
            int color = Color.HSVToColor(new float[] {110f, saturation, 1f});
            drawable.setColorFilter(color, Mode.SRC);
        }
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ViewHolder holder = (ViewHolder) view.getTag();
        holder.title.setText(cursor.getString(mFrom[0]));
        holder.description.setText(cursor.getString(mFrom[1]));

        // Get comments_count and set it as text
        int count = cursor.getInt(mFrom[2]);
        holder.comments_count.setText(count + "");
        holder.comments_count.setTag(cursor.getLong(0));

        // Adjust the color by saturation
        applyColorFilter(holder.comments_color, count);

        // Alternate method, that I explain in the answer
        //   Note: set the solid color in color.xml to #2aff00 
        //holder.comments_color.setAlpha(count * 45);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View view = mInflater.inflate(R.layout.list_item, parent, false);

        ViewHolder holder = new ViewHolder();
        holder.title = (TextView)view.findViewById(R.id.title);
        holder.description = (TextView)view.findViewById(R.id.description);
        holder.comments_count = (TextView)view.findViewById(R.id.comments_count);
        holder.comments_count.setOnClickListener(commentClick);
        holder.comments_color = ((LayerDrawable) holder.comments_count.getBackground()).findDrawableByLayerId(R.id.color);

        view.setTag(holder);

        return view;
    }

    @Override
    public Cursor swapCursor(Cursor newCursor) {
        if(mFrom == null && newCursor != null) {
            mFrom = new int[] {newCursor.getColumnIndex(TITLE), newCursor.getColumnIndex(DESCRIPTION), newCursor.getColumnIndex(COMMENTS_COUNT)};
        }
        return super.swapCursor(newCursor);
    }

    private class ViewHolder {
        TextView title;
        TextView description;
        TextView comments_count;
        Drawable comments_color;
    }
}

我做了一些改变:

  • mFrom 保存您正在使用的列的索引。您只需要获取列索引一次,它不会改变,除非您更改 Cursor
  • commentsClick一个通用的 OnClickListener,我将它用于每一行,并在创建 ViewHolder 时设置它
  • 我将您更改 HSV 颜色的方法引入了适配器,并将其命名为 applyColorFilter()
  • 我将 ViewHolder 的创建移到了 newView() 中,而不是在 bindView() 中检查 null >

行布局
您可能注意到我对评论的颜色做了一些不同的更改,这是因为我使用了更简单的行布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp" >

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/comments_count"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/description"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/title"
        android:layout_toLeftOf="@+id/comments_count"
        android:textAppearance="?android:attr/textAppearanceSmall" />

    <TextView
        android:id="@+id/comments_count"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="15dp"
        android:background="@drawable/comments_layers"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

(虽然 Thiago Moreira Rocha's layout 有效,但嵌套的 ViewGroup 似乎有点矫枉过正。任何时候你的 ViewGroup 只有一个 child ,他们通常是替代品。)

我用一个 LayerDrawable 来替换两个 LinearLayouts,我将在后面的步骤中解释。 首先,边框(border.xml),与上一个非常相似:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <corners android:radius="10dp" />
    <padding android:bottom="2dp" android:left="2dp" android:right="2dp" android:top="2dp" />
    <solid android:color="#ffffff" />
    <stroke android:width="2dp"
        android:color="#000000" />
</shape>

(注意填充是笔划的宽度。)

其次可调背景色(color.xml):

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <corners android:radius="10dp" />
    <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
    <solid android:color="#ffffff" />
</shape>

最后,我创建了一个 LayerDrawable 来组合两个图像 (comments_layers.xml):

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item 
        android:id="@+id/border"
        android:drawable="@drawable/border" />
    <item 
        android:id="@+id/color"
        android:drawable="@drawable/color" />
</layer-list>

(可选)
您在 applyColorFilter() 中调整了 HSV 值的饱和度,但这似乎等同于调整绿色背景的 alpha。如果这是真的,那么改变 alpha 值就是一个简单得多的任务。在 bindView() 中找到我的评论:

  1. 注释掉applyColorFilter(holder.comments_color, count);
  2. 取消注释 holder.comments_color.setAlpha(count * 45);
  3. 打开我的 color.xml 文件并将 solid 元素的 color 属性从 #ffffff 更改为#2aff00

事实上,我以前从未像这样使用过 LayerDrawables,可能有更快的方法,但我认为这非常巧妙。

关于android - 如何将多个触摸操作附加到单个列表项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12431592/

相关文章:

android - 想要使用 Android 设备的解析向用户发送用户通知

android - Material Design 按钮看起来更平滑且阴影更多

android - RecyclerView 或 ViewPager 或 ViewFlipper

android - 为什么这些按钮在 TableLayout 中没有对齐?

android - 显示/隐藏 ListView

Android:将空 View 设置为 ListView

javascript - 在Android上运行NodeJS的可行选项(2017年8月)

Android:如何在字符串定义中引用字符串

java - HttpClient 长时间停止,即使设置了超时参数

Android 向上滚动隐藏 View 和向下滚动显示 View 效果,如 twitter