首先,我看到了这个问题:Adding a colored background with text/icon under swiped row when using Android's RecyclerView
但是,即使标题用文本/图标"表示,但答案仅涵盖使用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>
我尝试重写方法OnChildDraw
:
// 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
),但有两个问题。
首先,它只画了一个小绿色方块包裹我的&#34;完成&#34;图标(下面屏幕截图中显示的视图的红色部分来自注释行choosePlanView.setBackgroundResource(R.color.delete_red);
)。在调试器中检查时,视图具有正确的宽度。
第二件事是放置图标的位置。我指定我希望它在水平方向上居中并且始终&#34;坚持&#34;在视图的右侧。然而,当滑动RecyclerView
项目并且红色背景显示它不在中心时,它会移动。
我尝试添加行choosePlanView.invalidate()
,因为我认为会发生这种情况,因为视图是先前创建的,但似乎重绘不会改变任何内容。
答案 0 :(得分:16)
使用ItemTouchUiUtil界面为此提供了强大的解决方案。它允许您在ViewHolder中拥有前景和背景视图,并将所有滑动处理委派给前景视图。以下是我用于向右滑动以移除的示例。
中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>
答案 1 :(得分:1)
我相信你应该使用viewType
而不是画画在适配器中实现getItemViewType(int position)
,返回不同类型,例如0表示正常,1表示翻转
并更改onCreateViewHolder等以在不同的viewType上返回不同的布局
答案 2 :(得分:1)
对于仍在查找此默认值的人,这是最简单的方法。
一个简单的实用程序类,可在向左或向右滑动时向RecyclerView项添加背景,图标和标签。
插入Gradle
implementation 'it.xabaras.android:recyclerview-swipedecorator:1.2.1'
重写ItemTouchHelper类的onChildDraw方法
@Override
public void onChildDraw (Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,float dX, float dY,int actionState, boolean isCurrentlyActive){
new RecyclerViewSwipeDecorator.Builder(MainActivity.this, c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
.addBackgroundColor(ContextCompat.getColor(MainActivity.this, R.color.my_background))
.addActionIcon(R.drawable.my_icon)
.create()
.decorate();
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
更多信息-> https://github.com/xabaras/RecyclerViewSwipeDecorator
答案 3 :(得分:0)
我设法通过扩展Sanvywell在Adding a colored background with text/icon under swiped row when using Android's RecyclerView
提供的答案来使用颜色和图像。我不会重新创建完整帖子(您可以点击链接)。简而言之,我没有创建一个完整的视图来在滑动过程中渲染,但只是在画布上添加了一个位图,适当地定位到RecyclerView项目。
答案 4 :(得分:-2)
我正在调查同样的问题。我最终做的是,在包含recyclerView的布局中,我添加了一个简单的FrameLayout
,称为'swipe_bg',其高度与我的RecyclerView.ViewHolder
项之一相同。我将其可见性设置为“已消失”,并将其置于RecyclerView
然后在我设置ItemTouchHelper
的活动中,我像这样重写onChildDraw ..
final ItemTouchHelper.SimpleCallback swipeCallback = new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT){
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
View itemView = viewHolder.itemView;
swipe_bg.setY(itemView.getTop());
if(isCurrentlyActive) {
swipe_bg.setVisibility(View.VISIBLE);
}else{
swipe_bg.setVisibility(View.GONE);
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
};
不知道这是不是最好的方式,但似乎是最简单的方式。