我想展开/折叠我的recyclerView的项目以显示更多信息。我想实现SlideExpandableListView的相同效果。
基本上在我的viewHolder中,我有一个不可见的视图,我想做一个平滑的展开/折叠动画,而不是将可见性设置为仅VISIBLE / GONE。我只需要一次扩展一个项目,可以稍微抬高以显示该项目已被选中很酷。
这与新的Android最近通话记录列表的效果相同。仅当选择一个项目时,选项“ CALL BACK”和“ DETAILS”才可见。
我想展开/折叠我的recyclerView的项目以显示更多信息。我想实现SlideExpandableListView的相同效果。
基本上在我的viewHolder中,我有一个不可见的视图,我想做一个平滑的展开/折叠动画,而不是将可见性设置为仅VISIBLE / GONE。我只需要一次扩展一个项目,可以稍微抬高以显示该项目已被选中很酷。
这与新的Android最近通话记录列表的效果相同。仅当选择一个项目时,选项“ CALL BACK”和“ DETAILS”才可见。
Answers:
请不要使用任何库来实现此效果,而应根据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>
TransitionManager.beginDelayedTransition(recyclerView);
如果我无法使用回收站视图引用,那将是解决方案。
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;
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);
}
});
完成!!简单而谦逊.. :)
OnClickListener
s移至,onCreateViewHolder
而不是onBindViewHolder
RecyclerView
工作完成,我的意思是,LayoutManager
如果它不管理布局,那还有什么意义呢!该解决方案具有较少的代码,可以RecyclerView
处理更多事情,并且效果更好,因此它比最受欢迎的解决方案更好。
并不是说这是最好的方法,但它似乎对我有用。
完整的代码可以在以下位置找到:示例代码: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);
}
}
使用布局更改的系统默认动画,一次只能扩展一项。至少对我有用。希望能帮助到你。
expandAlarm
函数AlarmClockFragment.java
执行扩展部分。
onClick()
我应该覆盖哪个?onClick
适配器中没有。
有一个非常简单的库,带有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()
我知道原始问题发布已经有很长时间了。但是我认为,对于像我这样的慢者,对@Heisenberg的答案进行一些解释会有所帮助。
在适配器类中声明两个变量为
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;
}
希望这可以帮助。
根本不需要使用第三方库。一个小调整的方法证明了谷歌I / O 2016和海森堡关于这一主题,做的伎俩。
以来 notifyDataSetChanged()
重新绘制完成RecyclerView
,notifyDataItemChanged()
是一个更好的选择(不是最好的),因为我们的位置和ViewHolder
我们所掌握,并notifyDataItemChanged()
只重绘特别ViewHolder
在给定位置。
但是问题在于,ViewHolder
即使notifyDataItemChanged()
使用,单击的过早消失和出现也无法消除。
以下代码 并非求助于notifyDataSetChanged()
或notifyDataItemChanged()
经过API 23的测试,在RecyclerView上使用时,其工作原理像一个超级按钮,其中每个ViewHolder CardView
的根元素均带有a :
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
是初始化为-1的全局整数。
details
是完整视图,展开后显示,折叠后隐藏。
如前所述,的根元素ViewHolder
是CardView
with foreground
和stateListAnimator
属性,其定义与Heisenberg对此主题的定义完全相同。
更新:如果其中一个处于展开状态,则以上演示将折叠先前扩展的项目。要修改此行为并使展开的项目保持原样,即使展开另一个项目,您也需要以下代码。
if (row.details.getVisibility()!=View.VISIBLE)
{
row.details.setVisibility(View.VISIBLE);
row.root.setActivated(true);
row.details.animate().alpha(1).setStartDelay(500);
}
else
{
row.root.setActivated(false);
row.details.setVisibility(View.GONE);
row.details.setAlpha(0);
}
TransitionManager.beginDelayedTransition(recycler);
更新:展开列表中的最后一项时,由于展开的部分位于屏幕下方,因此可能无法使其完全可见。要在屏幕上获取完整的项目,请使用以下代码。
LinearLayoutManager manager = (LinearLayoutManager) recycler.getLayoutManager();
int distance;
View first = recycler.getChildAt(0);
int height = first.getHeight();
int current = recycler.getChildAdapterPosition(first);
int p = Math.abs(position - current);
if (p > 5) distance = (p - (p - 5)) * height;
else distance = p * height;
manager.scrollToPositionWithOffset(position, distance);
重要信息:为了使以上演示工作正常进行,必须在其代码中保留RecyclerView及其LayoutManager的实例(为灵活性起见,请稍后参见)
notifyItemChanged
因为我ImageView
从URL中加载了哪个图像。notifyItemChanged
重新加载我的图像使其看起来很奇怪
TransitionManager.beginDelayedTransition(recycler);
,很棒的发现。但是我发现,通过使用此方法,如果我依次垃圾邮件单击几行,最终将触发内部崩溃The specified child already has a parent. You must call removeView() on the child's parent first
。我想这是由于回收者视图边界上的视图回收而引起的,但是我不确定。有人遇到过同样的问题吗?
在使用建议的方法来实现驻留在RecyclerView上由HeisenBerg回答的RecyclerView展开/折叠项目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)
为针对特定项目和一些小调整。
修改后,以前的不良影响应该消失了。但是,这可能不是完美的解决方案。它只做了我想要的,消除了眼神。
::编辑::
为了澄清起见,mExpandedPosition
和mExpandedHolder
均为全局变量。
notifyItemChanged()
。您可以手动设置动画并更改项目的高度,并在其中添加视图。
将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();
}
}
我认为应该会有所帮助,这就是我在最近的通话视图中实现并执行与Google相同的方式。
我很惊讶还没有一个简明的答案,尽管仅用两行代码就可以很容易地实现这种展开/折叠动画:
(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
//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);
}
}
在中使用两种视图类型RVAdapter
。一个用于扩展布局,另一个用于折叠。
在视频中0:42 设置android:animateLayoutChanges="true"
了RecyclerView
Checkout效果会产生神奇的效果