我想扩展/折叠我的recyclerView的项目,以显示更多信息。我想达到与SlideExpandableListView相同的效果。
基本上在我的viewHolder中我有一个不可见的视图,我想做一个平滑的展开/折叠动画,而不是仅将可见性设置为VISIBLE / GONE。我一次只需要一个项目进行扩展,如果有一个高程来显示该项目已被选中,那将会很酷。
它与新Android最近通话记录列表的效果相同。选项“CALL BACK”和“DETAILS”仅在选择项目时可见。
请不要使用任何库来实现此效果,而是根据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>
//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
中使用两种视图类型。一个用于扩展布局,另一个用于折叠。设置android:animateLayoutChanges="true"
为RecyclerView
的魔法发生了结果在this video 0:42使用这个实现的效果
不是说这是最好的方法,但似乎对我有用。
完整代码可以在以下位置找到:示例代码: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);
}
}
这应该一次只扩展一个项目,使用系统默认动画进行布局更改。至少它对我有用。希望能帮助到你。
为此,只需要简单的线条就不复杂了
在你的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);
}
});
完成!!!简单而谦逊.. :)
有一个非常简单易用的库,有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()
根本不需要使用第三方库。在Google I / O 2016和海森堡就此主题演示的方法中进行了一些调整,可以解决问题。
由于notifyDataSetChanged()
重绘完整的RecyclerView
,notifyDataItemChanged()
是一个更好的选择(不是最好的)因为我们有位置和ViewHolder
我们可以使用,而notifyDataItemChanged()
只重绘特定位置的特定ViewHolder
。
但问题是,即使使用ViewHolder
,notifyDataItemChanged()
在点击时的过早消失也不会消除。
以下代码不依赖于notifyDataSetChanged()
或notifyDataItemChanged()
并且在API 23上进行测试,并且在RecyclerView上使用时就像魅力一样,其中每个ViewHolder都有一个CardView
作为它的根元素:
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
,其中foreground
和stateListAnimator
属性的定义完全如海森堡所述。
更新:如果其中一个扩展,上述演示将折叠previosuly扩展项目。要修改此行为并保持扩展项目,即使展开另一个项目,您还需要以下代码。
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的实例(后者的灵活性)
在使用RecyclerView
回答的RecyclerView expand/collapse items上的HeisenBerg中实现的可扩展/可折叠项目的推荐方法之后,每当通过调用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
都是全局的。
我知道自原始问题发布以来已经很长时间了。但我认为对于像我这样缓慢的人来说,@ Heisenberg的回答会有所帮助。
在适配器类中声明两个变量as
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;
}
希望这可以帮助。
将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();
}
}
我认为这应该有所帮助,这就是我实施的方式,并在最近的通话视图中做了同样的谷歌。
您可以使用ExpandableLayout。 https://github.com/KyoSherlock/ExpandableLayout
这个ExpandableLayout就像一个平滑的展开/折叠动画CheckBox,所以它可以在任何地方使用(ListView或RecyclerView)。