Skip to content
Davide Steduto edited this page Sep 30, 2018 · 87 revisions

To Final

❗️ Child view clicks

The callback onItemClick has now a new parameter: View, that will help to distinguish which view has generated the click event. Most useful for child views in the itemView. Sample usage:

ViewHolder implementation

// To invoke in the constructor. "This" is the ViewHolder instance
// which already implements the onClick by default
button.setOnClickListener(this);

Optional implementation for custom callbacks:

@Override
public void onClick(View view) {
    if (view.getId() == R.id.buttonId) {
        // Button inner-view click: do something.
        // For example, call another custom callback.
    } else {
        // Item view click.
        // Automatic callback to Activity/Fragment implementation.
        super.onClick(view);
    }
}

OnItemClickListener implementation

⚠️ Warning: Old method onItemClick(int position) has been removed with this release.

@Override
public boolean onItemClick(View view, int position) {
    // Is itemView or innerView? view.getId() == ....
    return ...
}

❗️ Multi filter

Filter can now be of any type, extending the possibility to apply a multi filter simultaneously on more fields. IFilterable signature has now a parameter type, so the filter() method can accept the specified custom type.
New methods substitute the old ones when managing the filter:

Old methods New methods
setSearchText(String) -> setFilter(Serializable)
String getSearchText() -> MyFilter getFilter(MyFilter.class)
boolean hasSearchText() -> boolean hasFilter()
boolean hasNewSearchText(String) -> boolean hasNewFilter(Serializable)

If filter object is of type String, automatic trim and lowercase is maintained when setting it. Filter object must be of type Serializable in order to maintain save/restore instance state on configuration changes. String it is.

⚠️ Warning:

  • Old methods have been removed with this release.
  • Always specify parameter class type for FlexibleAdapter<common-item-type> to allow to recognize also the filter type! Do it in the activity/fragment as well!

Example with custom type (multi filter)

It's your choice to implement an inclusive (any match) or exclusive (all match) filter, here an exclusive example is shown:

public class ... extends ... implements IFilterable<MyFilter> {
    @Override
    public boolean filter(MyFilter constraint) {
        boolean result = true;
        if (constraint.isElectricCarSet()) {
            result = this.electric == constraint.isElectric());
        }
        if (result && constraint.isPriceSet()) {
            result = this.price <= constraint.getPrice());
        }
        return result;
    }

    @Override **WRONG**
    public void bindViewHolder(FlexibleAdapter adapter, // Wrong! (missing item type)
                               MyViewHolder holder,
                               int position,
                               List payloads) {         // Wrong! (missing list type)
        // Incompatible types: Required 'com.x.y.z.MyFilter' Found 'java.io.Serializable'
        MyFilter filter = adapter.getFilter(MyFilter.class);
    }

    @Override **CORRECT**
    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, // Must be IFlexible
                               MyViewHolder holder,
                               int position,
                               List<Object> payloads) {            // Must be Object
        // getFilter() can now recognize the type and can return MyFilter type
        MyFilter filter = adapter.getFilter(MyFilter.class);
    }
}

Helper class to show an empty view when Recycler View has no items. To better handle FastScroller, initialize this helper class after setting FastScroller to the Adapter. This helper supports:

  • Empty View in normal state.
  • Empty View for no filter result.
  • FastScroller handling if previously set into the Adapter.

This Helper class is very simple: User provides pre-configured empty views for data and filter results, the helper will show and hide the views in accordance with the Adapter callbacks. Usage:

Class location 👓

eu.davidea.flexibleadapter.helpers
  |_ EmptyViewHelper

Include your custom layout after RecyclerView widget:

<android.support.v7.widget.RecyclerView
    .../>

<!-- EmptyView layout for RV when empty -->
<include layout="@layout/empty_view"/>

<!-- EmptyView layout for RV when filter has empty result -->
<include layout="@layout/filter_view"/>

Examples: empty_view.xml, filter_view.xml

Usage (with fragments)

// Minimum usage
EmptyViewHelper.create(mAdapter, getView().findViewById(R.id.empty_view));

// Extended usage
EmptyViewHelper.create(mAdapter,
        getView().findViewById(R.id.empty_view),
        getView().findViewById(R.id.filter_view),
        // Optional in case of further customization
        (EmptyViewHelper.OnEmptyViewListener) getActivity());

DiffUtil is back

I've restored the support for DiffUtil, because it is still an acceptable solution, even though, the internal calculation seems faster on real devices but it gives worst results on emulator. However, both solutions are again available.

ℹ️ Tip: It's up to the developer, to choose which method to adopt, which flag to enable/disable in any case and sub-case.

Key methods are:

// FlexibleAdapter
boolean isAnimateChangesWithDiffUtil();
setAnimateChangesWithDiffUtil(boolean);
setDiffUtilCallback(FlexibleAdapter.DiffUtilCallback);

// IFlexible item interface
shouldNotifyChange(newItem);

Fixes and others changes can be read in 5.0.0 release page.


To RC4

❗️ UI extension 👓

Some Common, Helper and Util classes have been moved to a new library: this made the Adapter library thinner and without the direct dependency of Support Design library. The package signature remains the same.

implementation 'eu.davidea:flexible-adapter-ui:x.y.z'
eu.davidea.flexibleadapter
.common
  |_ FlexibleItemAnimator
  |_ FlexibleItemDecoration
  |_ SmoothScrollGridLayoutManager
  |_ SmoothScrollLinearLayoutManager
  |_ SmoothScrollStaggeredLayoutManager
  |_ TopSnappedSmoothScroller
.helpers
  |_ ActionModeHelper
  |_ AnimatorHelper
  |_ UndoHelper
.utils
  |_ DrawableUtils
  |_ FlexibleUtils

❕ LayoutUtils

Some Util methods are needed by the Adapter, therefore they are kept in the main library and grouped in the new class LayoutUtils moved from FlexibleUtils.

❗️ Revised again UndoHelper

New behavior for Action.UPDATE: now it doesn't remove items anymore:

  • If timeout is over, user is responsible to proceed with a confirmation action (may still be a deletion).
  • If undo Snackbar button is pressed, the action is cancelled and user should perform a notifyChange on those positions.
  • No change for Action.REMOVE, items are removed automatically.
// Class UndoHelper is now available in package UI, with same signature.
// More on this in the migration wiki page when ready.
implementation 'eu.davidea:flexible-adapter-ui:<version>'
package eu.davidea.flexibleadapter.helpers.UndoHelper;

// Renamed callback interface
from OnUndoListener to OnActionListener

// Use of the constants from annotation interface "Action" instead of class constants
constant ACTION_REMOVE to Action.REMOVE
constant ACTION_UPDATE to Action.UPDATE

// New parameter for method onActionCancelled provides the positions affected
// by the action (when the action button in Snackbar is pressed)
void onActionCanceled(@Action int action);
// to
void onActionCanceled(@Action int action, List<Integer> positions);

Also, fixed the consecutive item swiping when the option is enabled: every swiped item is correctly removed from the RecyclerView.

New callbacks onViewAttached & onViewDetached

New methods callbacks in IFlexible interface to support use cases of items with Audio/Video/GiFs. AbstractFlexibleItem has these new methods empty to speed up the development and the necessary methods abstract, so I suggest to extend from this class.

Independent item animation on reverse scrolling

Forward scrolling and Reverse scrolling are now independent. Call these methods to enable/disable them:

// deprecated
setAnimationOnScrolling(boolean)
boolean isAnimationOnScrollingEnabled

// new
setAnimationOnForwardScrolling(boolean)
setAnimationOnReverseScrolling(boolean)
boolean isAnimationOnScrollingEnabled
boolean isAnimationOnReverseScrollingEnabled

removeListener may accept the instance

The method removeListener(@NonNull Object listener) can now accept the instance of the listener or the Class object (as before) if the instance is not available.


To RC3

LiveData Extension

With RC3 release, I publish also an independent library (in beta version) to support the new Android Arch library. Please, I would like you will start to use it and eventually give suggestions for improvements. The LiveData extension should simplify the transformation of live items from any Repository to any Adapter.

ℹ️ Note: Wiki page for LiveData Extension is now ready 😃

Item View Type

FlexibleAdapter auto-mapping is now based on the return value of getItemViewType in IFlexible. This gives flexibility to reuse same Layout for multiple item types as explained in #430. For who inherits from AbstractFlexibleItem, this change is transparent.

ℹ️ Note: You should stick to implement only getLayoutRes() to identify an unique viewType, since getItemViewType is optional for advanced usage and exceptional cases.

CustomTags in logs

Different TAGs for multiple Adapter instances can now be set, usage example:

FlexibleAdapter.useTag("OverallAdapter");
mAdapter = new OverallAdapter(getActivity());

❗️ Revised UndoHelper

  • Deprecated OnActionListener in UndoHelper also onPreAction() and onPostAction().
    New comprehensive methods name: Renamed the 2 callbacks methods in OnUndoListener and renamed also the method remove series:
.withAction(int action, OnActionListener listener) >>> .withAction(@Action int action)
.remove(...) >>> .start(...) // Still returns Snackbar object

OnActionListener >>> !!deprecated!! // Please read related javaDoc

OnUndoListener.onDeleteConfirmed(int action) >>> onActionConfirmed(@Action int action, int event)
OnUndoListener.onUndoConfirmed(int action) >>> onActionCanceled(@Action int action)
  • Consecutive Undo requests option & improved the general stability. New method to commit one by one the swiped items and undo only the latest action. Also, it will clear the internal memory references at the end of the dismissal event!
.withConsecutive(true/false) // Default value is false (accumulate items to undo)
  • Added the type of event with the following cases:
onActionConfirmed(@Action int action, int event);
- DISMISS_EVENT_SWIPE = 0;       // Snackbar was dismissed via a swipe.
- DISMISS_EVENT_TIMEOUT = 2;     // Snackbar was dismissed via a timeout.
- DISMISS_EVENT_MANUAL = 3;      // Snackbar was dismissed via a call to dismiss().
- DISMISS_EVENT_CONSECUTIVE = 4; // Snackbar was dismissed from a new Snackbar being shown.
  • While the onActionCanceled is always called because of event type "action" only (user pressed on snackbar action button) and therefore not provided.
onActionCanceled(@Action int action);
- DISMISS_EVENT_ACTION = 1;      // Snackbar was dismissed via an action click.

❗️ Small breaking changes on sticky header implementation

  • setStickyHeaderElevation now accepts only dpi value!
  • OnStickyHeaderChangeListener receives also the last sticky header position. I couldn't deprecate the method.

❕ Removal of all deprecated functions

As announced long time ago, deprecated functions and classes are now permanently removed from library. New deprecated methods in this release will be removed in final version.

New sub-features worth to mention here:

  • Dynamically add and remove listeners.
  • New methods in IFlexible: getItemViewType() & getBubbleText();
  • New methods in FlexibleAdapter: getSubPositionOf() & getSameTypePositionOf().
  • New utility methods highlightWords() & highlightText() with multi-span in same text.
  • Upgrade to Support Library v26.
  • Remaining details of changes and fixes can be read in RC3 pre-release page.

To RC2

New interesting features for FastScroller

When set, by default it auto-hides. It is now independent from FlexibleAdapter (use of a delegate). More details in issue #34.

Endless scrolling in both directions

If activated with setTopEndless(), items can only be inserted at the top of the list, top endless is complementary to the bottom endless.

You can make compatible any third LayoutManagers with FlexibleAdapter by implementing it with IFlexibleLayoutManager and assign it to the RecyclerView as usual.

  • Can add equal space to all sides of items and the offset is customizable based on the view type.
  • Recognizes the sections of FlexibleAdapter and can add gap offset between them.
  • Recognizes the orientation of the current Layout.
  • Supports the default and also custom dividers.
  • etc....

❕ List copy is made inside

Adapter now makes a copy of the provided list (new ArrayList(userList)) at startup, updateDataSet and filterItems, before applying features, as consequence you should remove the copy of the list in these 3 situations.

❕ Changing variable names to set selection mode

Use the interface Mode to pick up the selection mode (constants MODE_* are now deprecated). For instance:

mAdapter.setMode(Mode.MULTI);

However, if you use the ActionModeHelper, the update is already done.

❗️ Simpler way to create ViewHolder

Unfortunately, you will have to adapt the method createViewHolder() in ALL of your IFlexible implementation. Now the inflated view is already provided so it will simplify the user code. The IFlexible interface now wants you to implement the method as following:

@Override
public MyViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
    return new MyViewHolder(view, adapter);
}

❗️ Get rid of Method B to create and bind ViewHolders

Method B is the classic way to implement the Adapter by overriding onCreateViewHolder() & onBindViewHolder(). Those methods will be now declared final, because Method A will be the new standard.

From now on, we will use only Method A: we will delegate the previous operations to the item interfaces. Item interfaces will now mandatory implement the following methods:

  • getLayoutRes()
  • createViewHolder()
  • bindViewHolder()

❗️ Important changes on methods:

  • onPostUpdate() and onPostFilter() now require to call super() otherwise the emptyView won't get notified!
  • updateDataSet() and filterItems() have hidden items (headers & expanded items) inserted before applying the features, so they won't get notified for removing and adding same items, but only for updating. This will improve performance avoiding useless notifications.
  • You can choose if an item will be rebound or not: shouldNotifyChange(IFlexible newItem) has been added to IFlexible interface, enabled by default. Override to change behaviour.

❗️ Important changes on classes:

  • Renamed DividerItemDecoration to FlexibleItemDecoration.
  • Renamed Utils to FlexibleUtils.

❕ Removed use case of Undo in combination with Filter

Starting or resetting the Filter will immediately commit the deletion and will empty the bin of the deleted items. More precisely the next sequences of use cases are removed from the library.

  • Delete items > Start filter > Undo > Items were restored at the right positions and already filtered.
  • Start filter > Delete items > Resetting the filter > Undo > Items were restored at their original position.

Expected use cases / behaviors:

  • Delete items with Undo > Start filter > Commit is triggered > Filter is applied.
  • Start filter > Delete items with Undo > Undo > Items are restored at the filtered positions.
  • Start filter > Delete items with Undo > Change filter again > Commit is triggered > New Filter is applied.

❕ Update to support library 25.4.0

From https://developer.android.com/topic/libraries/support-library/setup.html:

The support libraries are now available through Google's Maven repository. You do not need to download the support repository from the SDK Manager.

Make sure that the repositories section includes a maven section with the "https://maven.google.com" endpoint.

allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com"
        }
    }
}

Details of changes and fixes can be read in RC2 pre-release page.


To RC1

A new big feature: Scrollable Headers and Footers.

  • 2 new properties EndlessTargetCount & EndlessPageSize to automatic disable the endless feature and to automatic display a message by updating the content of progressItem when the new noMoreLoad() method is invoked.
  • A new callback in the listener: noMoreLoad(int newItemsSize),
  • The onLoadMore callback has now 2 new parameters (int lastPosition, int currentPage). The old method has been removed already!
  • The progressItem is now a scrollable footer.

❗️ Refactoring and Deprecation

  • OnUpdateListener size: The parameter "size" now represents ONLY the main items count. Scrollable Headers and Footers are not counted if present.
  • Many functions have been Refactored and deprecated. The old code will be removed in the final release. You should upgrade your code before that deadline.
    For an accurate migration -> read issue #200.
// Deprecated
enableStickyHeader();
disableStickyHeaders();
getStickySectionHeadersHolder();
getStickyHeaderContainer();
setStickyHeaderContainer(ViewGroup stickyContainer);
... and more

// New
setStickyHeaders(boolean sticky);
// A custom layout can still be added
setStickyHeaders(boolean sticky, ViewGroup stickyContainer);

❕ Changes on Sticky Headers configuration

  • Reduced XML Configuration for sticky headers: Now we can remove the <include> of the mini layout from ours XMLs: The sticky_header_layout is generated at runtime, this is particularly useful in ViewPager use case or with multiple instances of the Adapter. However, we still need a FrameLayout to wrap the RecyclerView in case of sticky headers: Refresh Circle and FastScroller views need to stay on the top of the sticky header, the wrapping resolves that issue:
<!-- SwipeRefreshLayout is optional.
     And if you need to drag items, this layout must be disabled! -->
<android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/swipeRefreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- This FrameLayout is still mandatory ONLY IF sticky header is enabled. This
         layout will help to receive the inflated layout at runtime and to display the
         Refresh circle AND the FastScroll on the top of sticky_header_layout. -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:listitem="@layout/recycler_adapter_item"/>

        <!-- NOT NEEDED ANYMORE!! This layout is generated at runtime when
             sticky headers are enabled. So you can safely remove it. -->
        <!--<include layout="@layout/sticky_header_layout"/>-->

    </FrameLayout>

</android.support.v4.widget.SwipeRefreshLayout>
  • Transparent header and Elevation on header. Now, it is super easy to add the tranparency and elevation to the header item, the values are taken from the header item layout:
<RelativeLayout	xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#aa7e57c2" <--- transparent background
    android:elevation="5dp">       <--- elevation for header item + sticky header
    ...
</RelativeLayout>

But if not configured in the layout or is Zero, then you have 1 new method to obtain this effect: header item flat + sticky header elevated:

setStickyHeaderElevation(float stickyElevation);

🏅 Bonus from my researches:

  • Transparent Sticky Header with elevation at the same time
  • Surgery precision on header swapping :-)
  • Double background not visible anymore on header swapping, if transparency is set.
  • Fade animation on sticky header container, when sticky is enabled or disabled.

❕ Changes on selectAll() and clearSelection()

No more notifyItemRangeChanged() in selectAll() and clearSelection() methods: This means no more item binding!
Now, bound selectable ViewHolders will have the StateListDrawable background switching status (activated/normal) when I internally invoke FlexibleViewHolder.toggleSelection(), so that, all inner views can complete animations with no interruptions.

ℹ️ Note:

  • The cached ViewHolders are removed when they are recycled by the RecyclerView.
  • The ViewHolders must extend FlexibleViewHolder, otherwise, item binding still occurs.

Fixes and others changes can be read in RC1 pre-release page.

Clone this wiki locally