当前位置: 首页 > 知识库问答 >
问题:

在滑动的RecyclerView项下显示自定义视图

王亮
2023-03-14

首先,我看到了这个问题:在使用Android的RecyclerView时,在滑动行下添加带有文本/图标的彩色背景

然而,即使标题说明“With text/icon”,答案也仅涵盖使用canvas对象绘制矩形。

现在我已经实现了绘制绿色矩形;然而,我想让它更明显的是什么将发生的添加“完成”按钮,就像在下面的屏幕截图。

public class ChoosePlanView extends LinearLayout{

    public ChoosePlanView(Context context) {
        super(context);
        init();
    }

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

    public ChoosePlanView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init(){
        View v = inflate(getContext(), R.layout.choose_plan_view, null);
        addView(v);
    }
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" 
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/choose_green">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/doneIcon"
        android:layout_gravity="center_horizontal|right"
        android:src="@mipmap/done"/>

</LinearLayout>
// ChoosePlanView choosePlanView; <- that was declared and initialized earlier, so I don't have to create a new ChoosePlanView everytime in OnChildDraw();

ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {    

/*
    onMove, onSwiped omitted
*/
  public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
       View itemView = viewHolder.itemView;

       if(dX < 0){
            choosePlanView.invalidate();
            //choosePlanView.setBackgroundResource(R.color.delete_red);
            choosePlanView.measure(itemView.getWidth(), itemView.getHeight());
            choosePlanView.layout(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
            c.save();
            c.translate(choosePlanView.getRight() + (int) dX, viewHolder.getAdapterPosition()*itemView.getHeight());

            choosePlanView.draw(c);
            c.restore();
       }

       super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
  }
}

首先,它只画了一个绿色的小方块来包装我的“完成”图标(在下面的屏幕截图中看到的视图的红色部分来自注释行ChoosePlanView.SetBackgroundResource(r.color.delete_red);)。但是,在调试器中选中时,视图具有正确的宽度。

第二件事是图标放置的位置。我指定我希望它水平居中,并始终“贴”在视图的右侧。然而,当recyclerview项被刷时,它会移动,并且红色背景显示它也没有被放置在中心。

我尝试添加行chooseplanview.invalidate(),因为我认为会发生这种情况,因为该视图是早些时候创建的,但重绘似乎没有任何改变。

共有1个答案

巴帅
2023-03-14

使用ItemTouchUiUtil接口提供了一个健壮的解决方案。它允许您在ViewHolder中有一个前景和背景视图,并将所有的滑动处理委托给前景视图。这里是一个示例,我使用向右滑动删除。

在ItemTouchHelper.Callback中:

public class ClipItemTouchHelper extends ItemTouchHelper.SimpleCallback {

    ...

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (viewHolder != null){
            final View foregroundView = ((ClipViewHolder) viewHolder).clipForeground;

            getDefaultUIUtil().onSelected(foregroundView);
        }
    }

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView,
                            RecyclerView.ViewHolder viewHolder, float dX, float dY,
                            int actionState, boolean isCurrentlyActive) {
        final View foregroundView = ((ClipViewHolder) viewHolder).clipForeground;

        drawBackground(viewHolder, dX, actionState);

        getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY,
                actionState, isCurrentlyActive);
     }

    @Override
    public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
                                RecyclerView.ViewHolder viewHolder, float dX, float dY,
                                int actionState, boolean isCurrentlyActive) {
        final View foregroundView = ((ClipViewHolder) viewHolder).clipForeground;

        drawBackground(viewHolder, dX, actionState);

        getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY,
                actionState, isCurrentlyActive);
    }

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder){
        final View backgroundView = ((ClipViewHolder) viewHolder).clipBackground;
        final View foregroundView = ((ClipViewHolder) viewHolder).clipForeground;

        // TODO: should animate out instead. how?
        backgroundView.setRight(0);

        getDefaultUIUtil().clearView(foregroundView);
    }

    private static void drawBackground(RecyclerView.ViewHolder viewHolder, float dX, int actionState) {
        final View backgroundView = ((ClipViewHolder) viewHolder).clipBackground;

        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            //noinspection NumericCastThatLosesPrecision
            backgroundView.setRight((int) Math.max(dX, 0));
        }
    }
}

并在布局文件中定义前景视图和背景视图:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/clipRow"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

        <View style="@style/Divider"/>

        <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/row_selector"
        >

        <RelativeLayout
            android:id="@+id/clipBackground"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:background="@color/swipe_bg"
            tools:layout_width="match_parent">

            <ImageView
                android:layout_width="32dp"
                android:layout_height="32dp"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_centerVertical="true"
                android:layout_marginLeft="12dp"
                android:layout_marginStart="12dp"
                android:focusable="false"
                android:src="@drawable/ic_delete_24dp"
                tools:ignore="ContentDescription"/>

        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/clipForeground"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingBottom="@dimen/clip_vertical_margin"
            android:paddingLeft="@dimen/clip_horizontal_margin"
            android:paddingRight="@dimen/clip_horizontal_margin"
            android:paddingTop="@dimen/clip_vertical_margin" >

            <CheckBox
                android:id="@+id/favCheckBox"
                android:layout_width="@dimen/view_image_size"
                android:layout_height="@dimen/view_image_size"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:background="@android:color/transparent"
                android:button="@drawable/ic_star_outline_24dp"
                android:clickable="true"
                android:contentDescription="@string/content_favorite"
                />

             ...

        </RelativeLayout>

    </FrameLayout>

</LinearLayout>
 类似资料:
  • 我已经做了一些研究,我还没有找到一个示例或实现,允许您在滑动时将一个视图(下面的示例图像)放在RecyclerView下面。是否有人有任何例子或想法,如何实现这将不使用库。 下面是我如何实现扫瞄以解除职务。

  • 我正在开发一个使用ActionBarSherlock和SlidingMenu的Android应用程序。 现在,我显示打开菜单的按钮: 但我不想表现出来 这就是我设置滑动菜单的方式: 我怎么才能去掉那个 当我点击那个按钮时,我打开了滑动菜单。 更新: 在黑带回答之后,我做了以下事情: 样式。xml: 显示xml: 结果: 我可以看到绿色的Android!!!我不想看到它!!

  • 提前致谢 下面是我的plugin.xml

  • 仍然像这样显示和隐藏视图: 但如果我必须使用向上滑动和向下滑动动画来显示和隐藏,该怎么办

  • 我遇到了以下问题:我当前正在使用SurfaceHolder在一个SurfaceView上显示一个CameraPreview(CameraPreview)。所以它提到,我必须设置我的表面保持器的类型,像这样; 不幸的是,在此之后,设置将失败,因此我无法再在该画布上绘制。是否有可能在一个SurfaceView上绘制预览框架和自己的视图?

  • 我有一个项目,我使用日历视图,内置的日历为Android。 因此,我在完成本日历的某些特定任务时面临一些困难。我真的希望我能在StackOverflow上找到解决方案。 > 如果没有,那就停止阅读。 这就是我的问题: 我想显示一个下拉菜单从选定的一天,与一些元素,用户可以选择。如果用户选择某个元素,则下拉菜单的状态将仅在选定日期更改,即如果用户单击13/1,下拉菜单应显示10个元素。如果用户选择一