我想展开/折叠recyclerView的项目以显示更多信息。我希望实现SlideExpandableListView的相同效果。
基本上在我的viewHolder中我有一个不可见的视图,我想做一个平滑的展开/折叠动画,而不是仅将可见性设置为VISIBLE / GONE。我只需要一次扩展一个项目,如果有一个高程来显示该项目已被选中,那将会很酷。
这与新Android最近通话记录列表的效果相同。选项“CALL BACK”和“DETAILS”仅在选择项目时可见。
答案 0 :(得分:173)
请不要使用任何库来实现此效果,而是根据Google I / O使用推荐的方式。在recyclerView的 onBindViewHolder 方法中执行以下操作:
final boolean isExpanded = position==mExpandedPosition;
holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);
holder.itemView.setActivated(isExpanded);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mExpandedPosition = isExpanded ? -1:position;
TransitionManager.beginDelayedTransition(recyclerView);
notifyDataSetChanged();
}
});
对于您想要的炫酷效果,请将它们用作list_item属性:
android:background="@drawable/comment_background"
android:stateListAnimator="@animator/comment_selection"
其中comment_background是:
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize="true"
android:enterFadeDuration="@android:integer/config_shortAnimTime"
android:exitFadeDuration="@android:integer/config_shortAnimTime">
<item android:state_activated="true" android:drawable="@color/selected_comment_background" />
<item android:drawable="@color/comment_background" />
</selector>
和comment_selection是:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true">
<objectAnimator
android:propertyName="translationZ"
android:valueTo="@dimen/z_card"
android:duration="2000"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</item>
<item>
<objectAnimator
android:propertyName="translationZ"
android:valueTo="0dp"
android:duration="2000"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</item>
</selector>
答案 1 :(得分:67)
不是说这是最好的方法,但似乎对我有用。
完整代码可在以下位置找到: 示例代码:https://github.com/dbleicher/recyclerview-grid-quickreturn
首先,将展开的区域添加到单元格/项目布局中,并使封闭的单元格布局为animateLayoutChanges =“true”。这将确保展开/折叠动画:
<LinearLayout
android:id="@+id/llCardBack"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:animateLayoutChanges="true"
android:padding="4dp"
android:orientation="vertical">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|fill_horizontal"
android:padding="10dp"
android:gravity="center"
android:background="@android:color/holo_green_dark"
android:text="This is a long title to show wrapping of text in the view."
android:textColor="@android:color/white"
android:textSize="16sp" />
<TextView
android:id="@+id/tvSubTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|fill_horizontal"
android:background="@android:color/holo_purple"
android:padding="6dp"
android:text="My subtitle..."
android:textColor="@android:color/white"
android:textSize="12sp" />
<LinearLayout
android:id="@+id/llExpandArea"
android:visibility="gone"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:text="Item One" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:text="Item Two" />
</LinearLayout>
</LinearLayout>
然后,使您的RV Adapter类实现View.OnClickListener,以便您可以对所单击的项目执行操作。添加一个int字段以保存一个展开视图的位置,并将其初始化为负值:
private int expandedPosition = -1;
最后,实现ViewHolder,onBindViewHolder()方法并覆盖onClick()方法。如果它的位置等于“expandedPosition”,你将在onBindViewHolder中展开视图,如果不是,则隐藏它。您可以在onClick侦听器中设置expandedPosition的值:
@Override
public void onBindViewHolder(RVAdapter.ViewHolder holder, int position) {
int colorIndex = randy.nextInt(bgColors.length);
holder.tvTitle.setText(mDataset.get(position));
holder.tvTitle.setBackgroundColor(bgColors[colorIndex]);
holder.tvSubTitle.setBackgroundColor(sbgColors[colorIndex]);
if (position == expandedPosition) {
holder.llExpandArea.setVisibility(View.VISIBLE);
} else {
holder.llExpandArea.setVisibility(View.GONE);
}
}
@Override
public void onClick(View view) {
ViewHolder holder = (ViewHolder) view.getTag();
String theString = mDataset.get(holder.getPosition());
// Check for an expanded view, collapse if you find one
if (expandedPosition >= 0) {
int prev = expandedPosition;
notifyItemChanged(prev);
}
// Set the current position to "expanded"
expandedPosition = holder.getPosition();
notifyItemChanged(expandedPosition);
Toast.makeText(mContext, "Clicked: "+theString, Toast.LENGTH_SHORT).show();
}
/**
* Create a ViewHolder to represent your cell layout
* and data element structure
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView tvTitle;
TextView tvSubTitle;
LinearLayout llExpandArea;
public ViewHolder(View itemView) {
super(itemView);
tvTitle = (TextView) itemView.findViewById(R.id.tvTitle);
tvSubTitle = (TextView) itemView.findViewById(R.id.tvSubTitle);
llExpandArea = (LinearLayout) itemView.findViewById(R.id.llExpandArea);
}
}
这应该一次只扩展一个项目,使用系统默认动画进行布局更改。至少它对我有用。希望它有所帮助。
答案 2 :(得分:62)
为此,只需要简单的线条就不复杂了
在你的onBindViewHolder方法中添加以下代码
final boolean isExpanded = position==mExpandedPosition;
holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);
holder.itemView.setActivated(isExpanded);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mExpandedPosition = isExpanded ? -1:position;
notifyItemChanged(position);
}
});
mExpandedPosition 是一个初始化为-1的int全局变量
首先使用previousExpandedPosition = -1
声明一个全局变量然后
final boolean isExpanded = position==mExpandedPosition;
holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);
holder.itemView.setActivated(isExpanded);
if (isExpanded)
previousExpandedPosition = position;
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mExpandedPosition = isExpanded ? -1:position;
notifyItemChanged(previousExpandedPosition);
notifyItemChanged(position);
}
});
完成!!!。简单而谦逊...... :)
答案 3 :(得分:14)
有一个非常简单易用的库,支持gradle:https://github.com/cachapa/ExpandableLayout。
直接来自图书馆文档:
<net.cachapa.expandablelayout.ExpandableLinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:el_duration="1000"
app:el_expanded="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click here to toggle expansion" />
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Fixed height"
app:layout_expandable="true" />
</net.cachapa.expandablelayout.ExpandableLinearLayout>
在您标记可展开视图后,只需在容器上调用以下任何方法:expand()
,collapse()
或toggle()
答案 4 :(得分:8)
根本不需要使用第三方库。 Google I / O 2016 和Heisenberg在此主题中演示的方法中的小调整可以解决问题。
由于notifyDataSetChanged()
重新绘制完整的RecyclerView
,notifyDataItemChanged()
是更好的选择(不是最佳选择),因为我们有位置和{{1}我们可以使用ViewHolder
仅重绘特定位置的特定notifyDataItemChanged()
。
但问题是即使使用了ViewHolder
,ViewHolder
在点击及其出现时的过早消失也不会消除。
以下代码不会诉诸notifyDataItemChanged()
或notifyDataSetChanged()
并在API 23上进行测试,并且在RecyclerView上使用时就像魅力一样,其中每个ViewHolder都有{ {1}}作为它的根元素:
notifyDataItemChanged()
CardView
是一个初始化为-1的全局整数。
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final boolean visibility = holder.details.getVisibility()==View.VISIBLE;
if (!visibility)
{
holder.itemView.setActivated(true);
holder.details.setVisibility(View.VISIBLE);
if (prev_expanded!=-1 && prev_expanded!=position)
{
recycler.findViewHolderForLayoutPosition(prev_expanded).itemView.setActivated(false);
recycler.findViewHolderForLayoutPosition(prev_expanded).itemView.findViewById(R.id.cpl_details).setVisibility(View.GONE);
}
prev_expanded = position;
}
else
{
holder.itemView.setActivated(false);
holder.details.setVisibility(View.GONE);
}
TransitionManager.beginDelayedTransition(recycler);
}
});
是展开时展示的完整视图,折叠后会隐藏。
如上所述,prev_position
的根元素是details
,ViewHolder
和CardView
属性的定义与海森堡就此主题完全相同。
更新:如果其中一个已展开,则上述演示将折叠优先扩展的项目。要修改此行为并保持扩展项目,即使展开了其他项目,您也需要以下代码。
foreground
更新:展开列表中的最后一项时,可能无法使其完全可见,因为展开的部分位于屏幕下方。要获取屏幕中的完整项目,请使用以下代码。
stateListAnimator
重要事项:要使上述演示工作,必须在其代码中保留RecyclerView&amp;的实例。它的LayoutManager(灵活性较晚)
答案 5 :(得分:6)
我知道自原始问题发布以来已经很长时间了。但我认为对于像我这样缓慢的人来说@Hisenberg的回答会有所帮助。
在适配器类中声明两个变量
private int mExpandedPosition= -1;
private RecyclerView recyclerView = null;
然后在原来的答案中给出 onBindViewHolder 。
// This line checks if the item displayed on screen
// was expanded or not (Remembering the fact that Recycler View )
// reuses views so onBindViewHolder will be called for all
// items visible on screen.
final boolean isExpanded = position==mExpandedPosition;
//This line hides or shows the layout in question
holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);
// I do not know what the heck this is :)
holder.itemView.setActivated(isExpanded);
// Click event for each item (itemView is an in-built variable of holder class)
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// if the clicked item is already expaned then return -1
//else return the position (this works with notifyDatasetchanged )
mExpandedPosition = isExpanded ? -1:position;
// fancy animations can skip if like
TransitionManager.beginDelayedTransition(recyclerView);
//This will call the onBindViewHolder for all the itemViews on Screen
notifyDataSetChanged();
}
});
最后,在适配器覆盖
中获取recyclerView对象@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
this.recyclerView = recyclerView;
}
希望这有助于。
答案 6 :(得分:5)
使用推荐的方法实现RecyclerView expand/collapse items HeisenBerg {{3}}所应用的RecyclerView
实施的可展开/可折叠项目,RecyclerView
时我看到了一些明显的文物通过调用TransitionManager.beginDelayedTransition(ViewGroup)
和随后notifyDatasetChanged()
来刷新。
他最初的回答:
final boolean isExpanded = position==mExpandedPosition;
holder.details.setVisibility(isExpanded?View.VISIBLE:View.GONE);
holder.itemView.setActivated(isExpanded);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mExpandedPosition = isExpanded ? -1 : position;
TransitionManager.beginDelayedTransition(recyclerView);
notifyDataSetChanged();
}
});
修改:
final boolean isExpanded = position == mExpandedPosition;
holder.details.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
holder.view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mExpandedHolder != null) {
mExpandedHolder.details.setVisibility(View.GONE);
notifyItemChanged(mExpandedPosition);
}
mExpandedPosition = isExpanded ? -1 : holder.getAdapterPosition();
mExpandedHolder = isExpanded ? null : holder;
notifyItemChanged(holder.getAdapterPosition());
}
}
int
ViewHolder
请注意,方法TransitionManager.beginDelayedTransition(ViewGroup)
和notifyDataSetChanged()
已替换为notifyItemChanged(int)
,以定位特定项目和一些小调整。
修改后,之前不需要的效果应该消失。但是,这可能不是完美的解决方案。它只做我想要的,消除了眼睛。
<强> :: EDIT :: 强>
为了澄清,mExpandedPosition
和mExpandedHolder
都是全局的。
答案 7 :(得分:3)
将onClick侦听器设置为ViewHolder类后执行以下操作:
@Override
public void onClick(View v) {
final int originalHeight = yourLinearLayout.getHeight();
animationDown(YourLinearLayout, originalHeight);//here put the name of you layout that have the options to expand.
}
//Animation for devices with kitkat and below
public void animationDown(LinearLayout billChoices, int originalHeight){
// Declare a ValueAnimator object
ValueAnimator valueAnimator;
if (!billChoices.isShown()) {
billChoices.setVisibility(View.VISIBLE);
billChoices.setEnabled(true);
valueAnimator = ValueAnimator.ofInt(0, originalHeight+originalHeight); // These values in this method can be changed to expand however much you like
} else {
valueAnimator = ValueAnimator.ofInt(originalHeight+originalHeight, 0);
Animation a = new AlphaAnimation(1.00f, 0.00f); // Fade out
a.setDuration(200);
// Set a listener to the animation and configure onAnimationEnd
a.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
billChoices.setVisibility(View.INVISIBLE);
billChoices.setEnabled(false);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
// Set the animation on the custom view
billChoices.startAnimation(a);
}
valueAnimator.setDuration(200);
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
billChoices.getLayoutParams().height = value.intValue();
billChoices.requestLayout();
}
});
valueAnimator.start();
}
}
我认为这应该会有所帮助,这就是我实施的方式,并且在最近的通话视图中也是如此。
答案 8 :(得分:3)
您可以使用ExpandableLayout。 https://github.com/KyoSherlock/ExpandableLayout
这个ExpandableLayout就像一个平滑的展开/折叠动画CheckBox,所以它可以在任何地方使用(ListView或RecyclerView)。
答案 9 :(得分:3)
令我惊讶的是,还没有一个简明的答案,尽管仅用两行代码就可以很容易地实现这种展开/折叠动画:
(recycler.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false // called once
与
一起notifyItemChanged(position) // in adapter, whenever a child view in item's recycler gets hidden/shown
因此,对我来说,以下链接中的说明非常有用:https://medium.com/@nikola.jakshic/how-to-expand-collapse-items-in-recyclerview-49a648a403a6
答案 10 :(得分:1)
//Global Variable
private int selectedPosition = -1;
@Override
public void onBindViewHolder(final CustomViewHolder customViewHolder, final int i) {
final int position = i;
final GetProductCatalouge.details feedItem = this.postBeanses.get(i);
customViewHolder.lly_main.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectedPosition = i;
notifyDataSetChanged();
}
});
if (selectedPosition == i) {
if (customViewHolder.lly_hsn_code.getVisibility() == View.VISIBLE) {
customViewHolder.lly_hsn_code.setVisibility(View.GONE);
customViewHolder.lly_sole.setVisibility(View.GONE);
customViewHolder.lly_sole_material.setVisibility(View.GONE);
} else {
customViewHolder.lly_hsn_code.setVisibility(View.VISIBLE);
customViewHolder.lly_sole.setVisibility(View.VISIBLE);
customViewHolder.lly_sole_material.setVisibility(View.VISIBLE);
}
} else {
customViewHolder.lly_hsn_code.setVisibility(View.GONE);
customViewHolder.lly_sole.setVisibility(View.GONE);
customViewHolder.lly_sole_material.setVisibility(View.GONE);
}
}
答案 11 :(得分:0)
在RVAdapter
中使用两种视图类型。一个用于扩展布局,另一个用于折叠。
为android:animateLayoutChanges="true"
设置RecyclerView
就会发生魔力
在this video