Code Monkey home page Code Monkey logo

freeflow's Introduction

FreeFlow is no longer under development

We are no longer working on FreeFlow and have moved to RecyclerViews for similar functionality. Thanks for all your support and interest -Arpit Mathur

FreeFlow

A layout engine for Android that decouples layouts from the View containers that manage scrolling and view recycling. FreeFlow makes it really easy to create custom layouts and beautiful transition animations as layouts are changed.

FreeFlow is a composition based approach to Android Layouts. As opposed to default Android Layouts, FreeFlow Layouts are swappable at runtime which allows views to their new states smoothly. The fundamental difference here is that FreeFlow prefers Composition over Inheritance which makes the system a lot more adaptable.

Freeflow may be considered in "alpha". You can help in many ways, by reviewing and making suggestions on api's to actually finding bugs and submitting patches via pull requests.

FreeFlow is inspired by UI frameworks like UICollectionViews on iOS and the Spark Architecture in Flex.

Building Blocks

At the basic level, FreeFlow consists of 4 parts:

  • FreeFlowContainer: The core class that extends ViewGroup and places all Views inside it
  • FreeFlowLayout: The class thats responsible for defining the Rect's that the Container will use to position the Views.
  • FreeFlowLayoutAnimator: The animator that will animate the Views when their position Rect's are changed because of a change in the Layout
  • SectionedAdapter: The data adapter class that returns the View instances based on the data being rendered. Its modeled very closely to the List Adapters that are used in Android but also understand the concept of "Section" which might segment data into different parts (For example a user's contacts list may include Sections that hold names beginning with a particular character).

Additionally there are some helper classes like the DefaultLayoutAnimator that will transition views automatically as they get added, moved or removed and is pretty configurable. FreeFlow comes with some basic Layouts like HLayout, VLayout , HGridLayout and VGridLayout but its easy enough to create custom layouts (see the Artbook example's custom layout)

The Artbook example in this repository is a good example of whats possible with FreeFlow. You can download the .apk from the releases tab or see the experience on the video below:

Artbook demo project

Feedback/Support/Help

Join the Google+ community for questions or keeping up with upcoming features, releases, etc

If you have changes you'd like to commit to the repo, you will need to sign the [Comcast Contributor License Agreement](Comcast Contributor License Agreement (03-07-14).pdf) available at the root of this repository.

freeflow's People

Contributors

arpit avatar dmitry-zaitsev avatar jakewharton avatar jerrellmardis avatar kusand avatar nt4cats avatar simon-heinen avatar sklaman avatar yelinaung avatar ypresto 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

freeflow's Issues

Layout change while scrolling can cause issues

Sometimes the views disappear when a layout change is triggered while scrolling. Seems like the changed layout might use scrollX and Y values from the previous layout to figure out what views to lay out and then failing.

Scrolling issue

I noticed that if you start scrolling slowly up or down for a bit the container will start to scroll slightly in the other direction thus causing a jerky scrolling experience. It seems like this is occurring when Views are inflated or being loaded into the container. I'm able to reproduce the issue in the sample Artbook app as well. I'll try to get a video of the issue.

View clipping occurs after scrolling horizontally

I created a ViewGroup that extends RelativeLayout and adds support for rounded corners which you can find here: https://gist.github.com/jerrellmardis/9240278. This ViewGroup is used to display each cell in the grid. When the container initially displays all cells have nice rounded corners but as you scroll back and forth the some of the corners on the cells get clipped. Here's a couple screenshots to illustrate what I'm talking about.

Expected:
https://dl.dropboxusercontent.com/u/93908706/Screenshot_2014-02-28-17-26-36.png

Actual:
https://dl.dropboxusercontent.com/u/93908706/Screenshot_2014-02-28-17-26-55.png

The views that are affected seem a bit random. Here's my layout as well.

public class QuiltLayout extends FreeFlowLayoutBase implements FreeFlowLayout {

    private Context mContext;
    private HashMap<Object, FreeFlowItem> mProxies;
    private int mLargeItemSide;
    private int mRegularItemSide;

    public QuiltLayout(Context context) {
        mContext = context;
        mProxies = new HashMap<Object, FreeFlowItem>();
    }

    @Override
    public void setDimensions(int measuredWidth, int measuredHeight) {
        super.setDimensions(measuredWidth, measuredHeight);
        mRegularItemSide = mContext.getResources().getDimensionPixelSize(R.dimen.patch_width_1);
        mLargeItemSide = mContext.getResources().getDimensionPixelSize(R.dimen.patch_width_2);
    }

    @Override
    public void prepareLayout() {
        mProxies.clear();

        Section section = itemsAdapter.getSection(0);

        final float regularHeightHRatio = .4f;
        final float largeHeightHRatio = .6f;
        int h1 = Math.round(height * regularHeightHRatio);
        int h2 = Math.round(height * largeHeightHRatio);
        int xOffset = 0;

        for (int i = 0; i < section.getDataCount(); i++) {
            FreeFlowItem freeFlowItem = new FreeFlowItem();
            freeFlowItem.isHeader = false;
            freeFlowItem.itemIndex = i;
            freeFlowItem.itemSection = 0;
            freeFlowItem.data = section.getDataAtIndex(i);

            Rect r = new Rect();

            switch (i % 18) {
                case 0:
                    r.left = 0;
                    r.top = 0;
                    r.right = mLargeItemSide;
                    r.bottom = height;
                    break;
                case 1:
                    r.left = 2 * mRegularItemSide;
                    r.top = 0;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = h1;
                    break;
                case 2:
                    r.left = 2 * mRegularItemSide;
                    r.top = h1;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = height;
                    break;
                case 3:
                    r.left = 3 * mRegularItemSide;
                    r.top = 0;
                    r.right = r.left + mLargeItemSide;
                    r.bottom = h2;
                    break;
                case 4:
                    r.left = 3 * mRegularItemSide;
                    r.top = h2;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = height;
                    break;
                case 5:
                    r.left = 4 * mRegularItemSide;
                    r.top = h2;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = height;
                    break;
                case 6:
                    r.left = 5 * mRegularItemSide;
                    r.top = 0;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = h1;
                    break;
                case 7:
                    r.left = 5 * mRegularItemSide;
                    r.top = h1;
                    r.right = r.left + mLargeItemSide;
                    r.bottom = height;
                    break;
                case 8:
                    r.left = 6 * mRegularItemSide;
                    r.top = 0;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = h1;
                    break;
                case 9:
                    r.left = 7 * mRegularItemSide;
                    r.top = 0;
                    r.right = r.left + mLargeItemSide;
                    r.bottom = height;
                    break;
                case 10:
                    r.left = 9 * mRegularItemSide;
                    r.top = 0;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = h2;
                    break;
                case 11:
                    r.left = 9 * mRegularItemSide;
                    r.top = h2;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = height;
                    break;
                case 12:
                    r.left = 10 * mRegularItemSide;
                    r.top = 0;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = h1;
                    break;
                case 13:
                    r.left = 10 * mRegularItemSide;
                    r.top = h1;
                    r.right = r.left + mLargeItemSide;
                    r.bottom = height;
                    break;
                case 14:
                    r.left = 11 * mRegularItemSide;
                    r.top = 0;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = h1;
                    break;
                case 15:
                    r.left = 12 * mRegularItemSide;
                    r.top = 0;
                    r.right = r.left + mLargeItemSide;
                    r.bottom = h2;
                    break;
                case 16:
                    r.left = 12 * mRegularItemSide;
                    r.top = h2;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = height;
                    break;
                case 17:
                    r.left = 13 * mRegularItemSide;
                    r.top = h2;
                    r.right = r.left + mRegularItemSide;
                    r.bottom = height;
                    break;
            }

            r.offset(xOffset, 0);
            freeFlowItem.frame = r;
            mProxies.put(section.getDataAtIndex(i), freeFlowItem);

            if (i % 18 == 17) xOffset += 14 * mRegularItemSide;
        }
    }

    @Override
    public HashMap<Object, FreeFlowItem> getItemProxies(int viewPortLeft, int viewPortTop) {
        Rect viewport = new Rect(viewPortLeft, viewPortTop, viewPortLeft + width, viewPortTop + height);
        HashMap<Object, FreeFlowItem> ret = new HashMap<Object, FreeFlowItem>();

        for (Map.Entry<Object, FreeFlowItem> entry : mProxies.entrySet()) {
            FreeFlowItem p = entry.getValue();
            if (Rect.intersects(p.frame, viewport)) {
                ret.put(entry.getKey(), p);
            }
        }

        return ret;

    }

    @Override
    public FreeFlowItem getFreeFlowItemForItem(Object item) {
        return mProxies.get(item);
    }

    @Override
    public int getContentWidth() {
        if (itemsAdapter == null)
            return 0;

        int sectionIndex = itemsAdapter.getNumberOfSections() - 1;
        Section s = itemsAdapter.getSection(sectionIndex);

        if (s.getDataCount() == 0)
            return 0;

        Object lastFrameData = s.getDataAtIndex(s.getDataCount() - 1);
        FreeFlowItem fd = mProxies.get(lastFrameData);

        return fd.frame.left + fd.frame.width();
    }

    @Override
    public int getContentHeight() {
        return height;
    }

    @Override
    public FreeFlowItem getItemAt(float x, float y) {
        return ViewUtils.getItemAt(mProxies, (int) x, (int) y);
    }

    @Override
    public boolean verticalScrollEnabled() {
        return false;
    }

    @Override
    public boolean horizontalScrollEnabled() {
        return true;
    }

    @Override
    public void setLayoutParams(FreeFlowLayoutParams params){ }
}

Click triggered unnecessarily

I have implemented OnItemClickListener for the FreeFlowContainer, and I have added few items into the container, both scroll container and clicking on the item working good, but the issue is when I drag down from the first item the click event fired, also when I drag up the last item, the click event fired.

Move Viewport offset based item frame changes to the Container class

On the LayoutController level I dont really want to compute the viewport based offsets per item frame. All of this can happen at the Container level.

So this method should no longer be required:

public FrameDescriptor getFrameDescriptorForItemAndViewport(
                Object item, int viewPortLeft, int viewPortTop) 

Changing a layout should go through the View lifecycle

In setLayout, right now we do this:

if (frames != null && frames.size() > 0) {

---
} else {
    requestLayout();
}

This could be problematic. Layout changes trigger a bunch of add/remove views which will cause invalidation anyway. It may be fine to compute new rectangles at this time but at the end we should call requestLayout and lay things out during the layout pass

Gradle Support

Looks awesome! Is Gradle support/uploading to Maven Central coming?

Offscreen buffer

There is no offscreen buffer at the moment. A concrete example of where this can be seen is when an imageview that contains a network image moves off screen by just a little bit, it has to reload the image every time it comes back on screen.

I think we should add this functionality to the container class, possibly as a pixel count buffer, or row/column count buffer. The problem with row/column count is that that only makes sense for rectangular layouts (something that is not a requirement).

Controlled layout transitions?

Is there a way I can manually control the progress of a transition between layouts. Example: The pinching animation on Clear app. It's controlled by the progress of the pinch and not by time.

dynamic height - FreeFlowItem

Hi, I am using freeflowcontainer with VLayout, each item having an Image and caption under that, the height of the caption textview vary based on the amount of text populated into that, So I want to extend the height of each freeflowitem based on caption height, please help, thanks

Layout not computed after data invalidated

Steps to reproduce:

  1. Set adapter for FreeFlowContainer
  2. Add data to adapter
  3. Call dataInvalidated on FreeFlowContainer

dataInvalidated() executes shouldRecalculateScrollWhenComputingLayout = false which prevents the layout from getting recomputed.

FreeFlowPhotoGrid: Crash in VGrid layout when changing from bad vertical list appearance

To reproduce:

  1. Switch to VList format

  2. "Scroll w/ anim" until items are off-screen

  3. Hit "Scale"

    AndroidRuntime  D  Shutting down VM
          dalvikvm  W  threadid=1: thread exiting with uncaught exception (group=0x41575ba8)
    AndroidRuntime  E  FATAL EXCEPTION: main
                    E  Process: org.freeflow.examples.freeflowphotogrid, PID: 32459
                    E  java.lang.IllegalStateException: dimensions not set
                    E      at org.freeflow.layouts.VGridLayout.generateItemProxies(VGridLayout.java:93)
                    E      at org.freeflow.layouts.VGridLayout.getItemProxies(VGridLayout.java:171)
                    E      at org.freeflow.core.Container.moveViewport(Container.java:912)
                    E      at org.freeflow.core.Container$3.run(Container.java:838)
                    E      at android.os.Handler.handleCallback(Handler.java:733)
                    E      at android.os.Handler.dispatchMessage(Handler.java:95)
                    E      at android.os.Looper.loop(Looper.java:136)
                    E      at android.app.ActivityThread.main(ActivityThread.java:5017)
                    E      at java.lang.reflect.Method.invokeNative(Native Method)
                    E      at java.lang.reflect.Method.invoke(Method.java:515)
                    E      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
                    E      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
                    E      at dalvik.system.NativeStart.main(Native Method)
    

Horizontal Scroll broken?

Setting horizontalScrollEnabled() to false and setting the appropriate content width in getContentWidth() does not produce the desired effects when extending FreeFlowLayoutBase.

Can't set OnItemClickListener

Hi, I want to open another activity when you click an item, Please suggest how to set onItemClickListener for each item, Thanks

SectionAdapter cannot apparently take complex data as header

The SectionHeader seems to be keyed of the section.getSectionTitle() property. So sections can only have String values? Also in the hashmap, the String is used as keys. So if the String is the same, one of the two headers will automatically be repositioned.

Vertical Scroll is returning null

I am trying to implement the library but I got my head stuck on this issue can you please point me out what I am doing wrong ?

That's the debug info

03-07 11:29:00.979    1755-1755/com.project.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.project.app, PID: 1755
    java.lang.NullPointerException
            at com.comcast.freeflow.core.FreeFlowContainer.getViewChanges(FreeFlowContainer.java:615)
            at com.comcast.freeflow.core.FreeFlowContainer.moveViewport(FreeFlowContainer.java:1064)
            at com.comcast.freeflow.core.FreeFlowContainer.moveViewportBy(FreeFlowContainer.java:1004)
            at com.comcast.freeflow.core.FreeFlowContainer.onTouchEvent(FreeFlowContainer.java:848)
            at android.view.View.dispatchTouchEvent(View.java:7706)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2210)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1945)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2068)
            at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1515)
            at android.app.Activity.dispatchTouchEvent(Activity.java:2458)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2016)
            at android.view.View.dispatchPointerEvent(View.java:7886)
            at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3954)
            at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3833)
            at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3399)
            at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3449)
            at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3418)
            at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3525)
            at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3426)
            at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3582)
            at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3399)
            at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3449)
            at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3418)
            at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3426)
            at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3399)
            at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5602)
            at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5582)
            at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5553)
            at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5682)
            at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
            at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
            at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)
            at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:5655)
            at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:5701)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
            at android.view.Choreographer.doCallbacks(Choreographer.java:574)
            at android.view.Choreographer.doFrame(Choreographer.java:542)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispat

Here is my Fragment

package com.project.app.fragments;

import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.comcast.freeflow.core.AbsLayoutContainer;
import com.comcast.freeflow.core.FreeFlowContainer;
import com.comcast.freeflow.core.FreeFlowItem;
import com.comcast.freeflow.core.Section;
import com.comcast.freeflow.core.SectionedAdapter;
import com.comcast.freeflow.layouts.FreeFlowLayout;
import com.comcast.freeflow.layouts.VGridLayout;
import com.comcast.freeflow.layouts.VLayout;
import com.koushikdutta.urlimageviewhelper.UrlImageViewHelper;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

import de.keyboardsurfer.android.widget.crouton.Configuration;
import de.keyboardsurfer.android.widget.crouton.Crouton;
import de.keyboardsurfer.android.widget.crouton.Style;
import com.project.app.R;
import com.project.app.models.Event;
import com.project.app.models.Photo;
import com.project.app.models.User;
import com.project.app.models.Venue;
import com.project.app.ui.ArtbookLayout;
import com.project.app.utils.Fields;

public class VenueGalleryFragment extends Fragment {
    Activity venueActivity;
    FreeFlowContainer ffContainer;
    ArtbookLayout custom;
    FreeFlowLayout[] layouts;
    VenuePhotosListAdapter adapter;
    Venue venue;
    AsyncHttpClient client;
    RequestParams photosParams;
    User currentUser;
    List<Photo> photos = new ArrayList<Photo>();

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_venue_gallery, container, false);
        venue = (Venue) venueActivity.getIntent().getExtras().getSerializable("venue");

        ffContainer = (FreeFlowContainer) rootView.findViewById(R.id.ffcGallery);
        Display display = venueActivity.getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);

        custom = new ArtbookLayout();
        layouts = new FreeFlowLayout[]{custom};

        // Get the images
        client = new AsyncHttpClient();
        client.setTimeout(Fields.DEFAULT_TIMEOUT);
        currentUser = User.currentUser();
        photosParams = new RequestParams();

        adapter = new VenuePhotosListAdapter(venueActivity);
        ffContainer.setLayout(layouts[0]);
        ffContainer.setAdapter(adapter);

        client.get(Fields.GRAPH_VENUES_URL + "/" + venue.venueId + "/photos", photosParams, new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, JSONObject response) {
                venueActivity.setProgressBarIndeterminateVisibility(Boolean.FALSE);
                try {
                    JSONArray photosArray = response.getJSONArray("photos");
                    for (int i = 0; i < photosArray.length(); i++) {
                        JSONObject photo = photosArray.getJSONObject(i);
                        photos.add(Photo.fromJson(photo));
                    }

                } catch (JSONException e) {
                    e.printStackTrace();
                }
                adapter.update(photos);
                ffContainer.dataInvalidated();
                ffContainer.setOnItemClickListener(new AbsLayoutContainer.OnItemClickListener() {
                    @Override
                    public void onItemClick(AbsLayoutContainer parent, FreeFlowItem proxy) {

                    }
                });

                ffContainer.addScrollListener( new FreeFlowContainer.OnScrollListener() {

                    @Override
                    public void onScroll(FreeFlowContainer container) {
                    }
                });
            }
        });

        return rootView;
    }

    protected class VenuePhotosListAdapter implements SectionedAdapter {

        private Context context;
        private Section section;

        public VenuePhotosListAdapter(Context context) {
            this.context = context;
            section = new Section();
            section.setSectionTitle("Pics");
        }

        public void update(List<Photo> photos){

            for(Photo o : photos){
                section.getData().add(o);
            }
        }
        @Override
        public long getItemId(int section, int position) {
            return section * 1000 + position;
        }

        @Override
        public View getItemView(int sectionIndex, int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = LayoutInflater.from(context).inflate(R.layout.list_item_pic_view, parent, false);
            }
            ImageView img = (ImageView) convertView.findViewById(R.id.pic);
            Photo p = (Photo) (section.getData().get(position));
            UrlImageViewHelper.setUrlDrawable(img, p.imageUrl, getResources().getDrawable(R.drawable.logo));
            return convertView;
        }

        @Override
        public View getHeaderViewForSection(int section, View convertView,
                                            ViewGroup parent) {
            return null;
        }

        @Override
        public int getNumberOfSections() {
            if(section.getData().size() == 0) return 0;
            return 1;
        }

        @Override
        public Section getSection(int index) {
            return section;
        }

        @Override
        public Class[] getViewTypes() {
            return new Class[] { LinearLayout.class };
        }

        @Override
        public Class getViewType(FreeFlowItem proxy) {
            return LinearLayout.class;
        }

        @Override
        public boolean shouldDisplaySectionHeaders() {
            return false;
        }

    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        venueActivity = activity;
    }

}

No way to programmatically call a setSelectedItem() method

While reading the selectedItem is pretty easy, since the container uses the point where the touch began as the element that will be the selectedItem if the touch event completes, there is no programmatic way of setting the selected item.

Add a touch mode changed listener

Expose a callback method that would notify consumers when the touch mode has changed. For instance, this would allow consumers to set layer types and remove when scrolling starts and ends.

Add "scroll" functionality

Containers should dispatch scrollevents that OnScrollListeners can listen to

Additionally need to support these scroll methods:

 boolean scrollToItem(int sectionIndex, int itemIndex, boolean animated)
// returns a true if scroll actually happened or false if the item was already in viewport at the appropriate position

Test:

addScrollListener(new OnScrollListener(){
    onScroll(){
       //validate position of item in viewport
    }
})
scrollToItem(....)


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.