RecyclerView mở rộng / thu gọn các mục


145

Tôi muốn mở rộng / thu gọn các mục trong recyclerView của mình để hiển thị thêm thông tin. Tôi muốn đạt được hiệu quả tương tự của SlideExpandableListView .

Về cơ bản trong chế độ xem của tôi, tôi có một chế độ xem không hiển thị và tôi muốn thực hiện một hoạt ảnh mở rộng / thu gọn mượt mà thay vì chỉ hiển thị ở chế độ VISIBLE / Gone. Tôi chỉ cần một vật phẩm được mở rộng tại một thời điểm và thật tuyệt khi có một số độ cao để cho thấy rằng vật phẩm được chọn.

Đó là hiệu ứng tương tự của danh sách lịch sử cuộc gọi gần đây của Android. Các tùy chọn "GỌI TRỞ LẠI" và "CHI TIẾT" chỉ hiển thị khi một mục được chọn.

RecyclerView các mục có thể mở rộng


Tôi có một câu hỏi liên quan. Trong ứng dụng Đồng hồ, hoạt động đặt báo thức có một tính năng tương tự. Nó được thực hiện theo cách tương tự?
dùng2731584

Này, bạn đã có giải pháp? tôi cũng đang tìm kiếm giải pháp tương tự cho ứng dụng của mình.
Arpit Patel

Bạn đã tìm ra được giải pháp nào chưa?
Armin Ghoreishi

1
Tôi đã cập nhật cách thức được đề xuất theo Google I / O 2016. Xem câu trả lời của tôi stackoverflow.com/questions/27203817/iêu
Heisenberg

kiểm tra câu trả lời của tôi ở đây một stackoverflow
vị.com / a / 48092441/5962715

Câu trả lời:


192

Vui lòng không sử dụng bất kỳ thư viện nào cho hiệu ứng này thay vào đó hãy sử dụng cách thức được đề xuất theo Google I / O. Trong phương thức onBindViewHolder của recyclerView, hãy làm điều này:

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();
    }
});
  • Trong đó chi tiết là chế độ xem của tôi sẽ được hiển thị trên cảm ứng (chi tiết cuộc gọi trong trường hợp của bạn. Hiển thị mặc định.GONE).
  • mExpandedP vị trí là một biến int được khởi tạo thành -1

Và đối với các hiệu ứng tuyệt vời mà bạn muốn, hãy sử dụng các hiệu ứng này làm thuộc tính list_item của bạn:

android:background="@drawable/comment_background"
android:stateListAnimator="@animator/comment_selection"

trong đó comment_background là:

<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>

và bình luận_selection là:

<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>

22
Khi sử dụng mã này, hình ảnh mở rộng trông lạ. Mỗi khi mục hàng đầu biến mất và mọi thứ thay đổi một vị trí. Bạn đã bao giờ trải nghiệm một cái gì đó tương tự?
chris-pollux

6
Tôi cố gắng thực hiện hoạt hình nhưng tôi thực hiện điều này trên bộ điều hợp, nhưng điều gì sẽ là giải pháp cho việc TransitionManager.beginDelayedTransition(recyclerView);nếu tôi không thể truy cập tham chiếu chế độ xem tái chế.
Martín Serrano

2
@Ranveer Nó hoạt động loại. Tôi có hai recyclerViews khá giống nhau, nhưng nó chỉ hoạt động chính xác cho một. Không biết tại sao. @ MartínDaniel Bạn cần truyền recyclerViewtham số dưới dạng tham số cho hàm tạo cho bộ điều hợp
chris-pollux

26
Đây là một cách tiếp cận khủng khiếp. Tôi không thể tin rằng nó được khuyến nghị tại Google I / O. Ngay cả sau khi điều tra dự án Kẻ sọc và thực hiện tất cả các cách giải quyết cần thiết từ nó, hoạt hình vẫn gây ra một số trục trặc lớn trong RecyclerView, ví dụ: mục đầu tiên / cuối nhìn thấy biến mất sớm. Cũng cuộn trong khi hoạt hình chạy làm rối tung mọi thứ. Nói chung, tôi không nghĩ rằng việc khắc phục tất cả các vấn đề gây ra bởi phương pháp này có thể được gọi là "chỉ cần đặt một dòng và mọi thứ sẽ hoạt động" như quảng cáo.
Vitali Olshevski

6
Chúng ta có một số cách mới và dễ dàng hơn trong năm 2019 cho vấn đề này không?
Ponomarenko Oleh

76

Đối với điều này, chỉ cần các dòng đơn giản không phức tạp

trong phương thức onBindViewHolder của bạn thêm mã bên dưới

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);
    }
});

mExpandedP vị trí là một biến toàn cục int được khởi tạo thành -1

Đối với những người chỉ muốn một mục mở rộng và những người khác bị sụp đổ. Dùng cái này

đầu tiên khai báo một biến toàn cục với trướcExpandedP vị trí = -1

sau đó

    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);
        }
    });

Làm xong!!!. Đơn giản và khiêm tốn .. :)


giải pháp tuyệt vời. Ngoài ra, tôi khuyên bạn nên chuyển cài đặt OnClickListeners sang onCreateViewHolderthay vìonBindViewHolder
YTerle

1
Hoạt động rất tốt, về thời gian đã có một giải pháp hợp lý chỉ cho phép RecyclerViewthực hiện công việc, ý tôi là, LayoutManagernếu không thì nó sẽ quản lý bố cục! Giải pháp này tốt hơn giải pháp được bình chọn hàng đầu vì nó có ít mã hơn, cho phép RecyclerViewxử lý mọi việc và hoạt động tốt hơn!
Đánh dấu Keen

1
không hiểu làm thế nào để thêm chế độ xem "chi tiết". Nó có nên tĩnh cho mỗi người giữ? Điều gì sẽ xảy ra nếu với mỗi mục danh sách tôi cần thêm các chế độ xem khác nhau?
BekaBot

@BekaBot đó là quan điểm mà bạn muốn ẩn trong khi thu gọn vật phẩm
Kiran Benny Joseph

@KiranBennyJoseph vâng, tôi hiểu. Trong trường hợp này, quan điểm nên giống nhau cho tất cả các mục? Nếu tôi muốn các chế độ xem khác nhau cho các mục khác nhau thì sao?
BekaBot

72

Không nói đây là cách tiếp cận tốt nhất, nhưng nó có vẻ hiệu quả với tôi.

Mã đầy đủ có thể được tìm thấy tại: Mã ví dụ tại: https://github.com/dble Rich/recyclerview-grid-quickreturn

Trước hết, hãy thêm khu vực mở rộng vào bố trí ô / mục của bạn và đặt bố cục ô kèm theo animateLayoutChanges = "true". Điều này sẽ đảm bảo rằng việc mở rộng / thu gọn là hoạt hình:

<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>

Sau đó, làm cho lớp RV Adaptor của bạn triển khai View.OnClickListener để bạn có thể hành động đối với mục được nhấp. Thêm một trường int để giữ vị trí của một khung nhìn mở rộng và khởi tạo nó thành một giá trị âm:

private int expandedPosition = -1;

Cuối cùng, triển khai các phương thức ViewHolder, onBindViewHolder () của bạn và ghi đè phương thức onClick (). Bạn sẽ mở rộng chế độ xem trong onBindViewHolder nếu vị trí của nó bằng với "ExtendedPocation" và ẩn nó nếu không. Bạn đặt giá trị của ExtendedPocation trong trình nghe onClick:

@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);
    }
}

Điều này sẽ chỉ mở rộng một mục tại một thời điểm, sử dụng hoạt hình mặc định của hệ thống để thay đổi bố cục. Ít nhất nó làm việc cho tôi. Hy vọng nó giúp.


Tôi biết làm thế nào để chỉ giữ một mục được chọn. Tôi thực sự không biết làm thế nào để làm hoạt hình trên mục đó. Hoạt ảnh mở rộng / thu gọn với hoạt ảnh hệ thống mặc định trông không được mượt mà cho lắm.
stanete

1
Tôi chưa thử những điều sau đây, nhưng có vẻ như nó sẽ hoạt động. Kiểm tra câu trả lời tại: stackoverflow.com/a/26443762/2259418
MojoTosh

2
@ user2731584 - Tôi không nghĩ vậy. Nhìn vào (những gì tôi tin là) nguồn của họ, có vẻ như đồng hồ Lollipop đang sử dụng ListView để hiển thị danh sách các báo thức. Bố cục: android.googlesource.com/pl platform / pack / apps / DesktopClock / + / Giả Họ dường như có mã tùy chỉnh để làm động các mục mở rộng / thu gọn trong danh sách này. Xem nguồn sau: android.googlesource.com/pl
platform / packages / apps / DesktopClock / + / Kẻ

1
@MojoTosh bạn nói đúng. Họ đang sử dụng ListView và thực hiện hoạt hình bằng mã. expandAlarmchức năng trong AlarmClockFragment.javacác tập tin thực hiện phần mở rộng.
dùng2731584

4
Tôi onClick()nên ghi đè lên? Không có onClicktrong Adaptor.
Vicky Leong

15

Có một thư viện rất đơn giản để sử dụng với sự hỗ trợ của lớp: https://github.com/cachapa/ExpandableLayout .

Ngay từ tài liệu thư viện:

<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>

Sau khi bạn đánh dấu của bạn có thể mở rộng quan điểm, chỉ cần gọi bất kỳ các phương pháp trên thùng: expand(), collapse()hoặctoggle()


Đây vẫn là cách tốt nhất để làm điều đó? Tôi đang cố gắng làm theo những gì bạn đã viết. Tôi có một số chế độ xem tái chế mà tôi muốn mở rộng để hiển thị biểu đồ khi nhấp vào
xác nhận

10

Tôi biết đã lâu rồi kể từ khi câu hỏi ban đầu được đăng. Nhưng tôi nghĩ với những người chậm chạp như tôi một chút giải thích về câu trả lời của @ Heisenberg sẽ giúp ích.

Khai báo hai biến trong lớp bộ điều hợp là

private int mExpandedPosition= -1;
private RecyclerView recyclerView = null;

Sau đó, trong onBindViewHolder như được đưa ra trong câu trả lời ban đầu.

      // 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();
            }
        });

Và cuối cùng để có được đối tượng recyclerView trong ghi đè bộ điều hợp

@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);

    this.recyclerView = recyclerView;
}

Hi vọng điêu nay co ich.


3
Giải pháp tuyệt vời và đơn giản. Cải thiện nhỏ, sử dụng RecyclerView.NO_POSITION thay vì số ma thuật -1.
Casper Bang

8

Đơn giản là không cần sử dụng thư viện của bên thứ ba. Một chút tinh chỉnh trong phương pháp được trình bày trong Google I / O 2016 và Heisenberg về chủ đề này, thực hiện thủ thuật này.

notifyDataSetChanged() vẽ lại hoàn chỉnhRecyclerView , notifyDataItemChanged()là một lựa chọn tốt hơn (không phải là tốt nhất) bởi vì chúng tôi có vị trí và ViewHoldertheo ý của chúng tôi, và notifyDataItemChanged()chỉ vẽ lại cụ thể ViewHoldertại một vị trí nhất định .

Nhưng vấn đề là sự biến mất sớm của ViewHolderkhi nhấp và sự xuất hiện của nó không bị loại bỏ ngay cả khi notifyDataItemChanged()được sử dụng.

Đoạn mã sau không dùng đến notifyDataSetChanged()hoặc notifyDataItemChanged()và được thử nghiệm trên API 23 và hoạt động như một nét quyến rũ khi được sử dụng trên RecyclerView trong đó mỗi ViewHolder có một CardViewphần tử gốc như:

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_positionlà một số nguyên toàn cầu được khởi tạo thành -1. detailslà chế độ xem hoàn chỉnh được hiển thị khi mở rộng và che giấu khi thu gọn.

Như đã nói, phần tử gốc của ViewHolderlà a CardViewvới foregroundstateListAnimatorcác thuộc tính được xác định chính xác như đã nói của Heisenberg về chủ đề này.

CẬP NHẬT: Trình diễn trên sẽ thu gọn mục được mở rộng phổ biến nếu một trong số chúng được mở rộng. Để sửa đổi hành vi này và giữ một mục được mở rộng như ngay cả khi một mục khác được mở rộng, bạn sẽ cần mã sau đây.

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);

CẬP NHẬT: Khi mở rộng các mục cuối cùng trong danh sách, nó có thể không được hiển thị đầy đủ vì phần mở rộng nằm bên dưới màn hình. Để có được mục đầy đủ trong màn hình, sử dụng mã sau đây.

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);

QUAN TRỌNG: Để các trình diễn ở trên hoạt động, người ta phải giữ mã của họ một phiên bản của RecyclerView & it LayoutManager (sau này để linh hoạt)


Cảm ơn giải pháp này làm việc cho tôi. Tôi cố gắng tránh sử dụng notifyItemChangedvì tôi có một ImageViewhình ảnh tải từ url. notifyItemChangedtải lại hình ảnh của tôi làm cho nó trông kỳ lạ
Tam Huynh

Các dòng mà nó là TransitionManager.beginDelayedTransition(recycler);, tìm thấy tuyệt vời. Nhưng tôi phát hiện ra rằng bằng cách sử dụng phương pháp này, nếu tôi nhấp vào spam một vài hàng liên tục, cuối cùng nó sẽ gây ra sự cố nội bộ The specified child already has a parent. You must call removeView() on the child's parent first. Tôi tưởng tượng điều này là do chế độ xem tái chế trên giới hạn chế độ xem của người tái chế, nhưng tôi không thể chắc chắn được. Có ai có cùng một vấn đề?
Roger Oba

Đây vẫn là cách tốt nhất để làm điều đó? Tôi đang cố gắng làm theo những gì bạn đã viết. Tôi có một số chế độ xem tái chế mà tôi muốn mở rộng để hiển thị biểu đồ khi nhấp vào. Tôi gặp một thời gian khó khăn để hiểu chính xác những gì để làm
sourlemonaid

Có ai có ví dụ đầy đủ về việc thực hiện này? Tôi có nghĩa là một ví dụ mã làm việc. Xin vui lòng giúp đỡ. Tôi không thể hiểu làm thế nào để làm điều đó?
Munazza

7

Sau khi sử dụng cách thức được đề xuất để triển khai các vật phẩm có thể mở rộng / có thể thu gọn nằm trong một vật phẩm mở rộng / thu gọn RecyclerViewtrên RecyclerView được trả lời bởi HeisenBerg , tôi đã thấy một số tạo tác đáng chú ý mỗi khi RecyclerViewđược làm mới bằng cách gọi TransitionManager.beginDelayedTransition(ViewGroup)và sau đó notifyDatasetChanged().

Câu trả lời ban đầu của anh ấy:

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();
    }
});

Đã sửa đổi:

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());
    }
}
  • chi tiết là chế độ xem mà bạn muốn hiển thị / ẩn trong quá trình mở rộng / thu gọn mục
  • mExpandedP vị trí là một inttheo dõi các mục mở rộng
  • mExpandedHolder được ViewHoldersử dụng trong quá trình thu gọn vật phẩm

Lưu ý rằng phương thức TransitionManager.beginDelayedTransition(ViewGroup)notifyDataSetChanged()được thay thế bằng cách notifyItemChanged(int)nhắm mục tiêu mục cụ thể và một số điều chỉnh nhỏ.

Sau khi sửa đổi, các hiệu ứng không mong muốn trước đó sẽ biến mất. Tuy nhiên, đây có thể không phải là giải pháp hoàn hảo. Nó chỉ làm những gì tôi muốn, loại bỏ các mắt.

::BIÊN TẬP::

Để làm rõ, cả hai mExpandedPositionmExpandedHolderlà toàn cầu.


Vui lòng giải thích cách thức và nơi mExpandedHolder được khai báo và sử dụng?
Werner

1
@Werner Tôi đã chỉnh sửa câu trả lời để hiển thị nơi nó được khai báo. Việc sử dụng là trong chính đoạn trích cũng như mục đích. Nó được sử dụng để animate sụp đổ, mở rộng mục.
Chan Teck Wei

Tôi thích cách tiếp cận này nhất khi có liên quan đến hoạt hình, nhưng tôi có "độ mờ" nhỏ này khi nhấp vào mục. Bạn có biết điều đó cũng hay khác đi, đây có phải là do sử dụng notifyItemChanged () không? drive.google.com/file/d/1GaU1fcjHEfSErYF50otQGLGsIWkSyQSe/
kazume 15/03/18

Đúng. Giống như bạn đã đoán, nó được gây ra bởi notifyItemChanged(). Bạn có thể tự tạo hiệu ứng và thay đổi chiều cao của mục và thêm lượt xem vào đó.
Chan Teck Wei

@ChanTeckWei: giải pháp của bạn đang hoạt động tốt nhưng hình ảnh hàng nhấp nháy bất cứ khi nào tôi thu gọn hoặc mở rộng hàng mục tái chế..Có giải pháp nào cho việc này không?
Pragya Mendiratta 16/07/18

3

Thực hiện như sau sau khi bạn đặt trình nghe onClick thành lớp 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();
    }
}

Tôi nghĩ điều đó sẽ giúp ích, đó là cách tôi triển khai và thực hiện cùng một google trong chế độ xem cuộc gọi gần đây.


2

Tôi ngạc nhiên khi chưa có câu trả lời ngắn gọn, mặc dù một hoạt hình mở rộng / thu gọn như vậy rất dễ đạt được chỉ với 2 dòng mã:

(recycler.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false // called once

cùng với

notifyItemChanged(position) // in adapter, whenever a child view in item's recycler gets hidden/shown

Vì vậy, đối với tôi, những lời giải thích trong liên kết dưới đây thực sự hữu ích: https://medium.com/@nikola.jakshic/how-to-Exand-collapse-items-in-recyclerview-49a648a403a6


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);
        }
}

nhập mô tả hình ảnh ở đây


0

Sử dụng hai loại xem trong của bạn RVAdapter. Một cho bố trí mở rộng và khác cho sụp đổ. Và điều kỳ diệu xảy ra với cài đặt android:animateLayoutChanges="true"cho RecyclerView Checkout hiệu ứng đạt được bằng cách sử dụng lúc 0h42 trong video này


Tâm giải thích điều này tốt hơn? Tôi dường như không thể làm cho nó hoạt động được
chào

@sourlemonaid về cơ bản, bạn tạo nhiều kiểu xem cho danh sách như được giải thích trong stackoverflow.com/a/26245463/3731795 ... Bạn theo dõi chỉ mục mà mục đó được mở rộng và phần còn lại của các mục được thu gọn vào thời điểm đó . Bây giờ if (current_item_index == extend_item_index) {return VIEW_TYPE_EXPANDED} khác {reutrn VIEW_TYPE_COLLAPSED}
PenduDev 30/12/18
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.