Giter VIP home page Giter VIP logo

flexibleadapter's People

Contributors

arpinca avatar borisdamato avatar danielpassos avatar davideas avatar gwailotr0n5000 avatar jblejder avatar jeanpimentel avatar jlwatkins avatar johnjohndoe avatar jrcacd avatar lauren2020 avatar long1eu avatar magneticflux- avatar masc3d avatar ouyangzn avatar shymmq avatar stepansanda avatar zoopolitic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flexibleadapter's Issues

Sorting items?

Is there a way to sort items without inserting them at the correct position?

Thanks!

Add the concepts of isEnabled - isSelectable - isSwipeable - isDraggable

TODO
isEnabled = no simple nor single nor multi selection, no touchable.
isSelectable = no single nor multi selection, cannot be deleted by user, probably not touchable, ok to delete programmaticaly.
isSwipeable = just cannot be swiped
isDraggable = just cannot be dragged
isHidden = just cannot be visible

DONE
isExpanded
isHidden (for searchView)

Undo Helper

Should launch the SnackBar automatically and interact with the Adapter.

Sticky headers inside section

Is it possible to configure the FlexibleAdapter to have sticky headers inside a section, not above it?
What I mean is to have items look like so:

=== section name ===
== sticky header 1 ==
= item 1.1 =
= item 1.2 =
== sticky header 2 ==
= item 2.1 =
= item 2.2 =

The point is that the section names do not stick to the top of the screen but the sticky headers which are inside the sections do.

ItemAnimators coherent with AnimatorViewHolder

Item Animation should not overlap with Adapter Animation.
Modify ItemAnimators to be intercepted by AnimatorVH, that can return false to stop animator.

Add custom animation on children ItemViews.

Headers are shown multiple times

How I initialize my adapter:

mAdapter = new MyNewsFlexibleAdapter(new ArrayList<AbstractFlexibleItem>());
        mAdapter.setDisplayHeadersAtStartUp(true);//Show Headers at startUp!`

// And after I get my recycler view
mRecycler.setAdapter(mAdapter);
        mAdapter.enableStickyHeaders(3);

I have this method in my adapter

 public void addNews(List<News> newsList) {
        // create header
        int categoryId = newsList.get(0).categoryId;
        MyNewsHeaderItem header = new MyNewsHeaderItem(categoryId);
        // add items for header
        for (News news : newsList) {
            MyNewsSmallItem newsSmallItem = new MyNewsSmallItem(news, header);
            addItem(getItemCount(), newsSmallItem);
        }
        showAllHeaders();
    }

And this method is called multiple times, if I call this method for 2 times I would like to have something like this

  • header
  • item
  • item
  • header
  • item
  • item

And instead the first header is added twice!

  • header
  • header
  • item
  • item
  • header
  • item
  • item

If this method gets called 3 times, the first header would be added 3 times, the second one twice...

How can I fix this ? If I don't call showAllHeaders() the headers won't show up, and this method can be called any time..

EDIT :
I found a solution

 hideAllHeaders();
        showAllHeaders();

EDIT 2: this will cause a NPE at FlexibleAdapter 827

And another question, how can I completely clear the list? Without creating a new adapter of course..

Sticky headers are not pushing one another from screen when using grid layout manager.

Hi,
I am testing 5.0.0-b5 and found a bug in StickyHeaderHelper#translateHeader() on row 151. You are expecting next potential header on position 1. But if for example I use 3 columns in my grid, you will always get current header until all items in section are off the screen.

So you won't get this nice pushing of one header off the screen by another header.

I was able to reproduce this in your demo app, when I changed span count of grid to 3 and span size of all items except header to 1.

Anyway, thanks for great work.

Sample Project?

A working example would be greatly appreciated? The ExampleAdapter is not really clear since you renamed ManageLabelsAdapter to it, along with a plethora of "missing" classes associated with it. Thank you for the library.

Bug on Sample App

When clicking sub item or remove sub item, will be appear following error:

FATAL EXCEPTION: main Process: eu.davidea.examples.flexibleadapter, PID: 28911 java.lang.ClassCastException: eu.davidea.examples.models.SubItem cannot be cast to eu.davidea.examples.models.SimpleItem at eu.davidea.examples.flexibleadapter.MainActivity.extractTitleFrom(MainActivity.java:739) at eu.davidea.examples.flexibleadapter.MainActivity.onItemSwipe(MainActivity.java:492) at eu.davidea.flexibleadapter.FlexibleAdapter.onItemSwiped(FlexibleAdapter.java:2331) at eu.davidea.flexibleadapter.helpers.ItemTouchHelperCallback.onSwiped(ItemTouchHelperCallback.java:159) at android.support.v7.widget.helper.ItemTouchHelper$4.run(ItemTouchHelper.java:669) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5254) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

How to enable sticky headers?

My header model

` */
public class MyNewsBigItem extends AbstractFlexibleItem<MyNewsBigItem.ViewHolder> implements ISectionable<MyNewsBigItem.ViewHolder, MyNewsHeaderItem> {

private MyNewsHeaderItem mHeader;

@Override
public MyNewsHeaderItem getHeader() {
    return mHeader;
}

@Override
public MyNewsHeaderItem setHeader(MyNewsHeaderItem header) {
    mHeader = header;
    return header;
}

`
And my adapter looks like this:

`public class MyNewsFlexibleAdapter extends FlexibleAdapter {

public MyNewsFlexibleAdapter(List<AbstractFlexibleItem> items) {
    super(items);
    enableStickyHeaders(3);
    MyNewsHeaderItem h1 = createHeaderItem();
    MyNewsHeaderItem h2 = createHeaderItem();
    MyNewsHeaderItem h3 = createHeaderItem();
    MyNewsHeaderItem h4 = createHeaderItem();

    addItem(getItemCount(), h1);
    addItem(getItemCount(), createbigItem(h1));
    addItem(getItemCount(), createbigItem(h1));
    addItem(getItemCount(), createbigItem(h1));
    addItem(getItemCount(), createbigItem(h1));
    addItem(getItemCount(), h2);
    addItem(getItemCount(), createbigItem(h2));
    addItem(getItemCount(), createbigItem(h2));
    addItem(getItemCount(), createbigItem(h2));
    addItem(getItemCount(), createbigItem(h2));
    addItem(getItemCount(), createbigItem(h2));
    addItem(getItemCount(), h3);
    addItem(getItemCount(), createbigItem(h3));
    addItem(getItemCount(), h4);
    addItem(getItemCount(), createbigItem(h4));
    addItem(getItemCount(), createbigItem(h4));
    addItem(getItemCount(), createbigItem(h4));
    addItem(getItemCount(), createbigItem(h4));
}

`

Everything is shown correctly on the app, but the headers are not sticky. Where I'm wrong?
I've also tried to call the enableStickyHeaders after I set the adapter to the recyclerview. no success.

Sections hide/show

Special items can be identified as sections (such expandables or headers), they can be hidden or shown programmatically, adapter will reflect the change.

Review the example App

Add configuration Dialog or load new Activity to show all the power the library has.
Separate example with new Activities/Fragments, Sections with sticky headers, Expandable items, Expandable headers (to evaluate), Linear/Grid animations, Helpers use cases.

Divider at the end of a section

Using RecyclerView.ItemDecoration creates a divider after every row and header. Is there a way to have the divider only show at the end of a section? Or should I make the divider a row?

Section header 1
section item 1
section item 2
divider
Section header 2
section item 1 (no divider here)

Sticky Headers not working on 5.0.0-SNAPSHOT

I'm trying to follow what you have in the example app, but I can't get sticky headers to work with my app. The header view shows up but isn't sticky.

gradle

compile 'eu.davidea:flexible-adapter:5.0.0-SNAPSHOT'
maven {url = "https://oss.sonatype.org/content/repositories/snapshots/" } //For Snapshots

Adapter

public class RecentContactsAdapter extends FlexibleAdapter<AbstractFlexibleItem> {

    private final Context context;

    private List<GroupedRecentCall> groupedRecentCallList;
    private Map<String, String> callLogToPhoneMap;
    private List<AbstractFlexibleItem> recentCallsWithHeaders;
    private Map<Integer, LocalDataForRecentCall> localMap;

    public RecentContactsAdapter(Context context, List<AbstractFlexibleItem> recentCallsWithHeaders) {
        super(recentCallsWithHeaders);

        this.recentCallsWithHeaders = recentCallsWithHeaders;
        this.context = context;

        localMap = new HashMap<Integer, LocalDataForRecentCall>();

        callLogToPhoneMap = new HashMap<String, String>();
    }
}

Header

public class RecentContactHeaderItem extends AbstractHeaderItem<RecentContactHeaderItem.ViewHolder> {

    private String title;

    public RecentContactHeaderItem(String title) {
        super();
        this.title = title;}

    @Override
    public boolean equals(Object o) {
        if (o instanceof String) {
            String oo = (String) o;
            return oo.equals(this.title);
        }
        return false;
    }

    @Override
    public int getLayoutRes() {
        return R.layout.recent_contacts_header;
    }

    @Override
    public ViewHolder createViewHolder(FlexibleAdapter adapter, LayoutInflater inflater, ViewGroup parent) {
        return new ViewHolder(inflater.inflate(getLayoutRes(), parent, false), adapter);
    }

    @Override
    public void bindViewHolder(FlexibleAdapter adapter, ViewHolder holder, int position, List payloads) {
        holder.titleView.setText(title);
    }

    public static class ViewHolder extends FlexibleViewHolder {
        public OpenSansTextView titleView;

        public ViewHolder(View view, FlexibleAdapter adapter) {
            super(view, adapter);
            this.titleView = (OpenSansTextView) view.findViewById(R.id.title);
        }
    }
}

Section item

public class RecentContactItem extends AbstractSectionableItem<RecentContactItem.ViewHolder, RecentContactHeaderItem> {

    private final String TAG = "RecentContactItem";

    private Context context;
    private SimpleDateFormat timeFormatter;
    private SimpleDateFormat dateFormatter;
    private GroupedRecentCall groupedRecentCall;

    private Map<String, String> callLogToPhoneMap;
    private Map<Integer, RecentContactsAdapter.LocalDataForRecentCall> localMap;

    private RoundedTransformation roundedTransformer;
    private Bitmap defaultAvatar;

    public RecentContactItem(Context context, RecentContactHeaderItem header, SimpleDateFormat timeFormatter,
                             SimpleDateFormat dateFormatter, GroupedRecentCall groupedRecentCall,
                             HashMap<Integer, RecentContactsAdapter.LocalDataForRecentCall> localMap,
                             HashMap<String, String> callLogToPhoneMap) {
        this.context = context;
        setHeader(header);
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof CallLogObject) {
            GroupedRecentCall inItem = (GroupedRecentCall) o;
            return this.groupedRecentCall.getCallLogObject().getCallDate().equals(inItem.getCallLogObject().getCallDate());
        }
        return false;
    }

    @Override
    public int getLayoutRes() {
        return R.layout.recent_contacts_item;
    }

    @Override
    public ViewHolder createViewHolder(FlexibleAdapter adapter, LayoutInflater inflater, ViewGroup parent) {
        return new ViewHolder(inflater.inflate(getLayoutRes(), parent, false), adapter);
    }

    @Override
    public void bindViewHolder(FlexibleAdapter adapter, ViewHolder holder, int position, List payloads) {
        // binding
    }

public static final class ViewHolder extends FlexibleViewHolder {

        public ImageView avatarView;
        public OpenSansTextView moreCountView;
        public OpenSansTextView text1View;
        public OpenSansTextView text2View;
        public ImageView moreView;

        public ViewHolder(View view, FlexibleAdapter adapter) {
            super(view, adapter);

            avatarView = (ImageView) view.findViewById(R.id.avatar);
            moreCountView = (OpenSansTextView) view.findViewById(R.id.moreCount);
            text1View = (OpenSansTextView) view.findViewById(R.id.text1);
            text2View = (OpenSansTextView) view.findViewById(R.id.text2);
            moreView = (ImageView) view.findViewById(R.id.more);
        }
    }
}

Fragment (the rest of the view is instantiated in onCreateView

@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        FlexibleAdapter.enableLogs(true);

        Context context = getContext();

        if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED) {
            CallLogUtils.getAllCallsFromLog(context, null);// use null so its not a recursive call to this function
        }

        SimpleDateFormat timeFormatter = new SimpleDateFormat("h:mm a");
        SimpleDateFormat dateFormatter = new SimpleDateFormat("MMM d");

        HashMap<Integer, RecentContactsAdapter.LocalDataForRecentCall> localMap = new HashMap<>();
        HashMap<String, String> callLogToPhoneMap = new HashMap<>();

        List<GroupedRecentCall> groupedRecentCallList = ModelManager.getCallsGrouped(context);
        List<AbstractFlexibleItem> recentCallsWithHeaders = new ArrayList<>();

        RecentContactHeaderItem communcationStates = new RecentContactHeaderItem("Communication Stats");
        RecentContactHeaderItem frequentCallers = new RecentContactHeaderItem("Frequent callers");
        RecentContactHeaderItem recentActivity = new RecentContactHeaderItem("Recent activity");

        for (int i = 0; i < groupedRecentCallList.size(); i++) {
            GroupedRecentCall groupedRecentCall = groupedRecentCallList.get(i);
            RecentContactItem item = new RecentContactItem(context, (i < groupedRecentCallList.size() / 2) ? frequentCallers : recentActivity, timeFormatter,
                    dateFormatter, groupedRecentCall, localMap, callLogToPhoneMap);
            item.setHeader((i < groupedRecentCallList.size() / 2) ? frequentCallers : recentActivity);
            recentCallsWithHeaders.add(item);
        }

        adapter = new RecentContactsAdapter(context, recentCallsWithHeaders);

        recyclerView = (RecyclerView) getView().findViewById(R.id.list);
        recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
        // load adapter here for < 4.1
        recyclerView.setAdapter(adapter);
        recyclerView.setHasFixedSize(true);

//        listView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.setItemAnimator(new DefaultItemAnimator() {
            @Override
            public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
                return true;
            }
        });

        adapter.setDisplayHeadersAtStartUp(true);
        adapter.enableStickyHeaders();
}

Fragment layout

<?xml version="1.0" encoding="utf-8"?>
<!--- used by recent contacts and address book -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/list"
            android:background="@color/white"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v4.widget.SwipeRefreshLayout>

    <!-- needed for FlexibleAdapter sticky headers -->
    <include layout="@layout/sticky_header_layout"/>

    <include
        android:id="@android:id/empty"
        android:visibility="gone"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        layout="@layout/empty_layout" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleSmall"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_centerInParent="true"
        android:visibility="gone"/>

    <spokeo.com.spokeomobile.views.OpenSansTextView
        android:id="@+id/progressText"
        android:layout_below="@id/progressBar"
        android:layout_marginTop="10dp"
        android:gravity="center"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:text="Loading Connections"
        android:textColor="@color/dark_gray"
        android:visibility="gone"/>

</RelativeLayout>

Sticky Headers clickable

Once a header is drawn over others elements, it should be clickable.
This is not a bug due to the different representation/implementation of the view in the RecyclerView.

Filter using interface rather than just a string

Rather than just passing a String constraint to the filter method, it would be nice if you could pass an interface along the lines of:

boolean isAllowed(T item)

The item would be passed to the isAllowed method and allow you to filter items with different conditions.

I am happy to work on a PR for this. Just wanted to check if this was something you were interested in supporting.

New FastScroller

New FastScroller:

  • Autohide.
  • Improving configuration.
  • Bubble can be enabled/disabled and position tuned on Y axis too.
  • FastScrollerDelegate and Interface, to be used standalone outside of FlexibleAdapter (still inside the package).
  • IgnoreTouchesOutsideHandle
  • Extends / Separate the copyright for FastScroller in the readme.
  • Customizable minimum scroll amount to show the FastScroller.

Other sources:

Sticky headers

While scrolling, an header or a section can be "sticky" to the top (or to the bottom?).
It should pushed away when scrolling in favor of a new headers.

Bug: demo is weird when searching

  1. The top-left corner has a "..." button which does nothing
  2. Pressing the X button on the right closes the search, instead of just clearing the query
  3. pressing the back button (of the nav buttons) doesn't close the search, but instead it closes the activity.

Adjust and improve Wiki pages

Add a Wiki page with all functionalities and quick description of what the library can do.
Add and adjust Wiki pages with tutorials for v5.0.0 to show the main functionalities.
Add a side menu for different versions.

Status of the Wiki pages

The basics

  • Library structure
  • Setting Up
  • Setting Up Advanced
  • Item interfaces
  • ViewHolders
  • Callbacks
  • Migrations

Functionalities

  • Update Data Set
  • Selection modes
  • Headers and Sections
  • Scrollable Headers and Footers
  • Expandable items
  • Drag&Drop and Swipe
  • Search Filter
  • EndlessScroll / On Load More
  • Adapter Animations

Extensions

  • Smooth Layout Managers
  • Thirds Layout Managers
  • Flexible Item Decoration
  • FastScroller
  • Utils
  • ActionModeHelper
  • UndoHelper
  • AnimatorHelper
  • Payload

Demo App

  • Activity & Fragments

* = Initiated / Not completed

v5.0.0-b4: Inconsistency detected issue with showAllHeaders() method.

Hi @davideas

Thanks for great lib.

I am using FlexibleAdapter to display sticky headers in RecyclerView. It is working fine for the first time loading list data using adapter, however, I am getting below crash issue while pushing fresh list items in adapter for the second time onwards.

Below is my code.

Code in onCreateView() method:

mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));

        //mRecyclerView.setHasFixedSize(true); //Size of RV will not change
        mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
            @Override
            public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
                //NOTE: This allows to receive Payload objects on notifyItemChanged called by the Adapter!!!
                return true;
            }
        });
        mRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), R.drawable.divider));

code in refreshData() method:(which will be called everytime when user want to refresh data)

ArrayList<AbstractFlexibleItem> items = new ArrayList<AbstractFlexibleItem>();
.....
......
add AbstractFlexibleItem objects(headers and simple items) to items.
....
.......
mAdapter = new FeedAdapter(items, FeedFragment.this);
mAdapter.setRemoveOrphanHeaders(false);
mRecyclerView.setAdapter(mAdapter);
mAdapter.showAllHeaders();
mAdapter.enableStickyHeaders(3);

Note: FeedAdapter extends FlexibleAdapter

I am not observing the crash issue while commenting showAllHeaders() method call, however, no headers are showing due to this.

Can you please help me to get out of this issue?


E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.code, PID: 23833
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 15(offset:21).state:21
  at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4405)
  at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4363)
  at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961)
  at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370)
  at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333)
  at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:562)
  at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2864)
  at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3071)
  at android.view.View.layout(View.java:15140)
  at android.view.ViewGroup.layout(ViewGroup.java:4866)
  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
  at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
  at android.view.View.layout(View.java:15140)
  at android.view.ViewGroup.layout(ViewGroup.java:4866)
  at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1627)
  at android.view.View.layout(View.java:15140)
  at android.view.ViewGroup.layout(ViewGroup.java:4866)
  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1888)
  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1742)
  at android.widget.LinearLayout.onLayout(LinearLayout.java:1651)
  at android.view.View.layout(View.java:15140)
  at android.view.ViewGroup.layout(ViewGroup.java:4866)
  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
  at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
  at android.view.View.layout(View.java:15140)
  at android.view.ViewGroup.layout(ViewGroup.java:4866)
  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1888)
  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1742)
  at android.widget.LinearLayout.onLayout(LinearLayout.java:1651)
  at android.view.View.layout(View.java:15140)
  at android.view.ViewGroup.layout(ViewGroup.java:4866)
  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
  at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
  at android.view.View.layout(View.java:15140)
  at android.view.ViewGroup.layout(ViewGroup.java:4866)
  at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1888)
  at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1742)
  at android.widget.LinearLayout.onLayout(LinearLayout.java:1651)
  at android.view.View.layout(View.java:15140)
  at android.view.ViewGroup.layout(ViewGroup.java:4866)
  at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
  at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
  at android.view.View.layout(View.java:15140)
  at android.view.ViewGroup.layout(ViewGroup.java:4866)
  at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2342)
  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2048)
  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1211)
  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6282)
  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:788)
  at android.view.Choreographer.doCallbacks(Choreographer.java:591)
  at android.view.Choreographer.doFrame(Choreographer.java:560)
  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:774)
  at android.os.Handler.handleCallback(Handler.java:808)
  at android.os.Handler.dispatchMessage(Handler.java:103)
  at android.os.Looper.loop(Looper.java:193)
  at android.app.ActivityThread.main(ActivityThread.java:5341)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:515)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:825)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:641)
E/NativeCrypto: ssl=0x60990e98 cert_verify_callback x509_store_ctx=0x61259940 arg=0x0
E/NativeCrypto: ssl=0x60990e98 cert_verify_callback calling verifyCertificateChain authMethod=ECDHE_RSA

example not using List

I am trying to think on how to integrate your lib (5.0.0).
In my use case getting a List to use with the adapter is really an options.
I hold a list of sections which each holds a list of items and a possible header.
I wondering if there might be a way to use the FlexibleAdapter by subclassing it to get the item from my sections.
It seems doable but i might have issues making it work with all the features:

  • getItemCount: that method is final which means i can't do getItemCount = sectionsCount*ItemCount
  • showAllHeaders / hideAllHeaders / isHeaderShared seems to rely on mItems
  • filter / expand ... seems also to rely on mItems

I think this might require some refactoring to do things like this.
I also think it would be doable without changing anything performance wise.
For example:

public List<Integer> getExpandedPositions() {
        List<Integer> expandedPositions = new ArrayList<Integer>();
        for (int i = 0; i < mItems.size() - 1; i++) {
            T item = mItems.get(i);
            if (isExpanded(item))
                expandedPositions.add(i);
        }
        return expandedPositions;
    }

would become

public List<Integer> getExpandedPositions() {
        List<Integer> expandedPositions = new ArrayList<Integer>();
        for (int i = 0; i < getItemCount() - 1; i++) {
            T item = getItem(i);
            if (isExpanded(item))
                expandedPositions.add(i);
        }
        return expandedPositions;
    }

What do you think?

FYI i am trying to integrate your lib in my fork of the Titanium Mobile framework

*** Snapshots and Pre-Releases for FlexibleAdapter v5.0.0 ***

This is an open discussion to keep track of all the work in progress of the next coming pre-releases in order to arrive to a stable and final version.

In this major release (5.0.0) there will be lot of new features, while trying to simplify the configuration to speed up the development. A full list of the features and improvements, with their status, can be found here Milestone 5.0.0. However we can identify them in:

  • Expandable item with selection coherence.
  • Predefined ViewHolders.
  • Adapter Animations.
  • Drag&Drop and Swipe actions.
  • New concept of Item.
  • Simplify the constructor.
  • New FastScroller to include in the library.
  • Rewrite filtering and restore methods.
  • Headers/Sections
  • etc..

In order to do them, I am completely changing and refactoring the code, names and how the Adapter will be extended to override its methods.

Gradle configuration

allprojects {
    repositories {
        // For [pre-]releases
        jcenter()
        // For SNAPSHOT
        maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
    }
}
// Don't cache SNAPSHOT (changing) dependencies.
configurations.all {
    resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
dependencies {
    // JCenter for PreReleases
    compile 'eu.davidea:flexible-adapter:5.0.0-rc3'
    compile 'eu.davidea:flexible-adapter-livedata:1.0.0-b1'
    compile 'eu.davidea:flexible-adapter-databinding:1.0.0-b2'

    // Maven for SNAPSHOT
    compile ('eu.davidea:flexible-adapter:5.0.0-SNAPSHOT') {
        changing = true;
    }
}

As soon as a new SNAPSHOT is ready and usable I will communicate it here.

Suggestions

  • Feel free to Fork but better to advise me in advance what are you going to modify in order to coordinates the commits and the work.
  • Also, feel free to test and report back here or by opening a new Issue.

Naming convention adopted

Version Reason for publishing Description
5.0.0-SNAPSHOT continuous development A library with many changes that might be unstable, nice to have to early benefit of the latest bug fix, improvements and new features as soon as they are implemented.
It will replace the existent library (with that name) in the maven snapshot repository. So you don't have to manually change the version in the dependencies, but expect to upgrade your code in order to continue to compile your project.

Gradle has internal caching system with default time of 24h. Passed this time it will fetch the new Snapshot file from repository, if a new exists.
5.0.0-bX beta pre-release Usable beta library with some new features to test.
5.0.0-rcX release candidates Nearly completed library with good stability and improved features
5.0.0 release The stable library with all new features confirmed and tested.

Add unit tests

The project need to have some unit tests to help us to refactor/introduce new features.

updateDataSetAsync method doesn't give any added value

updateDataSetAsync() will be deprecated in 4.2.0 and removed from next major release.

The inner class FilterAsyncTask will not be used anymore to load data at startup: there's no advantage to use an Asynchronous loading, usually the list is already loaded Asynchronously somewhere else.

Populate list of items

It is not so clear only looking for the API or reading the wiki, you need populate the list of items in FlexibleAdapter using the method filterItems. If you don't do that you will get a RuntimeException.

IMHO populate the list of items should be a construction responsabilite. Wdyt?.

Example with checkbox

Could you provide an example with checkbox selection?
For some users a long click to select is sometimes "hard to understand" or in other words "they don't know what to do". ;-)

The adapter is highlighting text but not filtering

I have copied the two classes and extended the Flexible adapter class in my adapter. My problem now is when i enter text in search view the text gets highlighted but it does not get filtered. I know im going wrong somewhere but i cant figure out where. Below is the code of my adapter class.

    public class FertilizerListAdapter extends FlexibleAdapter<FertilizerListAdapter.FertilizerViewHolder, Fertilizer> {
    List<Fertilizer> items;
    Context context;
    LayoutInflater mInflater;
    public FertilizerListAdapter(Context context, List<Fertilizer> items, String param) {
        this.items = items;
        this.context = context;
        mInflater = LayoutInflater.from(context);
        updateDataSet(param);
    }
    @Override
    public void updateDataSet(String param) {

    }
    @Override
    public FertilizerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View productItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.fertilizer_list_item, parent, false);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
            productItem.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        FertilizerViewHolder productItemVH = new FertilizerViewHolder(productItem);
        return productItemVH;

    }

    @Override
    public void onBindViewHolder(FertilizerViewHolder holder, final int position) {
        Fertilizer item = items.get(position);
        Typeface custom_font = Typeface.createFromAsset(context.getAssets(), "fonts/RobotoSlab-Light.ttf");
        holder.mProductName.setText(items.get(position).sProductName);
        holder.mProductPrice.setText(items.get(position).sProductPrice);
        holder.mShortDesc.setText(items.get(position).sShortDesc);
        ColorGenerator generator = ColorGenerator.DEFAULT;
        int color = generator.getRandomColor();
        TextDrawable drawable = TextDrawable.builder()
                .beginConfig()
                .textColor(Color.WHITE)
                .toUpperCase()
                .useFont(custom_font)
                .fontSize(30)
                .endConfig()
                .buildRound(String.valueOf(items.get(position).sProductName.charAt(0)), color);

        Picasso.with(context)
                .load(items.get(position).sProductImage)
                .placeholder(drawable)
                .error(drawable)
                .into(holder.mProductImage);


        holder.itemView.setTag(item);
        if (hasSearchText()) {
            setHighlightText(holder.mProductName, item.sProductName, mSearchText);
            setHighlightText(holder.mShortDesc, item.sShortDesc, mSearchText);
        } else {
            holder.mProductName.setText(item.sProductName);
            holder.mShortDesc.setText(item.sShortDesc);
        }
        holder.mView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(context, FertilizerView.class);
                i.putExtra("ProductApplication", (items.get(position).sApplication));
                i.putExtra("ProductAvailability", (items.get(position).sAvailability));
                i.putExtra("ProductBenefits", (items.get(position).sBenefits));
                i.putExtra("ProductChemicalContent", (items.get(position).sChemicalContent));
                i.putExtra("ProductCrops", (items.get(position).sCrops));
                i.putExtra("ProductBacgroundImage", (items.get(position).sProductBackground));
                i.putExtra("ProductImage", (items.get(position).sProductImage));
                i.putExtra("ProductName", (items.get(position).sProductName));
                i.putExtra("ProductPrice", (items.get(position).sProductPrice));
                i.putExtra("ProductDescription", (items.get(position).sShortDesc));
                context.startActivity(i);
            }
        });
    }





    @Override
    public int getItemCount() {
        return items.size();
    }


    public static class FertilizerViewHolder extends RecyclerView.ViewHolder {
        ImageView mProductImage;
        TextView mProductName;
        TextView mShortDesc, mProductPrice;
        View mView;

        public FertilizerViewHolder(View itemView) {
            super(itemView);
            mView = itemView;
            mProductImage = (ImageView) itemView.findViewById(R.id.product_image);
            mProductName = (TextView) itemView.findViewById(R.id.product_name);
            mProductPrice = (TextView) itemView.findViewById(R.id.price);
            mShortDesc = (TextView) itemView.findViewById(R.id.shortDesc);

        }
    }
    private void setHighlightText(TextView textView, String text, String searchText) {
        Spannable spanText = Spannable.Factory.getInstance().newSpannable(text);
        int i = text.toLowerCase(Locale.getDefault()).indexOf(searchText);
        if (i != -1) {
            spanText.setSpan(new ForegroundColorSpan(Utils.getColorAccent(context)), i,
                    i + searchText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            spanText.setSpan(new StyleSpan(Typeface.BOLD), i,
                    i + searchText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            textView.setText(spanText, TextView.BufferType.SPANNABLE);
        } else {
            textView.setText(text, TextView.BufferType.NORMAL);
        }
    }
    @Override
    protected boolean filterObject(Fertilizer fertilizer, String constraint) {
        String valueText = fertilizer.sProductName;
        //Filter on Title
        if (valueText != null && valueText.toLowerCase().contains(constraint)) {
            return true;
        }
        //Filter on Subtitle
        valueText = fertilizer.sShortDesc;
        return valueText != null && valueText.toLowerCase().contains(constraint);
    }
    }

Make items expandable

Expandable and Not expandable items should have selection coherence, meaning that is not possible to select both View types.
Filtering should automatically expand the expandable if searchText exists in his subItems.

Animate items while filtering

Adapter should not call notifyDataSetChanged() anymore while filtering. Instead items should be added and/or removed from the adapter list depending by the searchText and the final change should be animated.

Add a FlexibleViewHolder

I was think about add a new utility class FlexibleViewHolder it will help developers it alwasy need to implements the View.OnClickListener and View.OnLongClickListener

public abstract class FlexibleViewHolder extends RecyclerView.ViewHolder
        implements View.OnClickListener, View.OnLongClickListener {

    private final FlexibleAdapter adapter;
    private final OnListItemClickListener onListItemClickListener;

    public FlexibleViewHolder(View itemView,FlexibleAdapter adapter,
                              OnListItemClickListener onListItemClickListener) {
        super(itemView);
        this.adapter = adapter;

        this.onListItemClickListener = onListItemClickListener;

        this.itemView.setOnClickListener(this);
        this.itemView.setOnLongClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (onListItemClickListener.onListItemClick(getAdapterPosition())) {
            toggleActivation();
        }
    }

    @Override
    public boolean onLongClick(View view) {
        onListItemClickListener.onListItemLongClick(getAdapterPosition());
        toggleActivation();
        return true;
    }

    protected void toggleActivation() {
        itemView.setActivated(adapter.isSelected(getAdapterPosition()));
    }

    public interface OnListItemClickListener {
        boolean onListItemClick(int position);
        void onListItemLongClick(int position);
    }

}

So you can easily override the toggleActivation to add whatever you want and implements the OnListItemClickListener on your Activiy/Fragment

Simplify constructors to handle multiple listeners at once

Simplify ALL constructors. The adapter should recognize which type of listener an Activity or a Fragment is implementing the events triggered by the User or by the adapter.
Give the possibility to Developers to decide which listeners to implement one by one.

Maybe pass 1 single parameter to represent all listeners that object belongs to, or use prefix-with methodology to set the listeners at startup.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.