GithubHelp home page GithubHelp logo

famous-flex's Introduction

Logo famous-flex

Animatable layouts, FlexScrollView & widgets for famo.us.

Screenshot

Above anything, famous-flex is a concept in which renderables are seperated from how they are layed-out. This makes it possible to change layouts on the fly and animate the renderables from one layout to another. For instance, you can layout a collection of renderables using a CollectionLayout, and change that into a ListLayout. When using flow-mode the renderables will smoothly transition from the old state to the new state using physics, particles and springs.

Demos

Getting started

Core concepts

Views / widgets

Resources

Installation

Install using bower or npm:

bower install famous-flex

npm install famous-flex

LayoutController

LayoutController is a view that lays out renderables based on:

  • a layout-function
  • a data-source containing renderables
  • optional layout-options

Example of laying out renderables using a CollectionLayout:

var LayoutController = require('famous-flex/LayoutController');
var CollectionLayout = require('famous-flex/layouts/CollectionLayout'); // import standard layout

// create collection-layout
var layoutController = new LayoutController({
    layout: CollectionLayout,
    layoutOptions: {
        itemSize: [100, 100],
        gutter: [20, 20],
        justify: true
    },
    flow: true,    // smoothly animates renderables when changing the layout
    direction: 1,  // 0 = X, 1 = Y, undefined = use default from selected layout-function
    dataSource: [
        new Surface({content: 'surface1'}),
        new Surface({content: 'surface2'}),
        new Surface({content: 'surface3'})
    ]
});
this.add(layoutController); // add layout-controller to the render-tree

When the flow option is enabled, renderables are animated smoothly between layout states.

Layout function

A layout is represented as a Function, which takes a context argument and an optional options argument. The purpose of the function is to lay-out the renderables in the data-source by calling context.set() on a renderable. The renderables can be enumerated by calling context.next(), context.prev() or by using the id of the renderable.

Famous-flex comes shipped with various standard layouts, but it is also very easy to create your own layout-functions. View LayoutContext for more details on creating your own layout-functions.

/**
 * @param {LayoutContext} context Context used for enumerating renderables and setting the layout
 * @param {Object} [options] additional layout-options that are passed to the function
 */
function LayoutFunction(context, options) {

    // simple layout-function that lays out renderables from top to bottom
    var node = context.next();
    var y = 0;
    while (node) {
        context.set(node, {
            size: [context.size[0], 100],
            translate: [0, y, 0]
        });
        y += 100;
        node = context.next();
    }
};

For optimal performance, the layout function is only executed when:

  • A resize occurs
  • An option is changed on the layout-controller
  • When the content is scrolled

Datasource

The data-source contains the renderables that are to be layed-out. It can be one of three things:

  • An Array
  • A LinkedListViewSequence
  • A VirtualViewSequence
  • An Object with key/value pairs

In case of an Array or a ViewSequence, use context.next() in your layout-function to enumerate all the renderables in the data-source:

var layoutController = new LayoutController({
    layout: function (context, options) {
        var y = 0;
        var node = context.next();
        while (node) {
            context.set(node, {
                size: [context.size[0], 100],
                translate: [0, y, 0]
            });
            y += 100;
            node = context.next();
        }
    },
    dataSource: [
        new Surface({content: 'surface1'}),
        new Surface({content: 'surface2'}),
        new Surface({content: 'surface3'})
    ]
});

Sometimes it is easier to identify renderables by an id, rather than a sequence. In that case use context.get() or directly pass the data-source id to the context.set() function:

var layoutController = new LayoutController({
    layout: function (context, options) {
        context.set('one', {
            size: [100, 100],
            translate: [0, 0, 0]
        });
        context.set('two', {
            size: [100, 100],
            translate: [100, 0, 0]
        });
        context.set('three', {
            size: [100, 100],
            translate: [200, 0, 0]
        });
    },
    dataSource: {
        'one': new Surface({content: 'one'}),
        'two': new Surface({content: 'two'}),
        'three': new Surface({content: 'three'})
    }
});

Layout literals

Layout literals are objects which describe layouts through a definition rather than a function. The following example describes the use of a layout literal using dock semantics (see LayoutDockHelper):

var layoutController = new LayoutController({
    layout: {dock: [
        ['top', 'header', 50],
        ['bottom', 'footer', 50],
        ['fill', 'content']
    ]},
    dataSource: {
        header: new Surface({content: 'Header'}),
        footer: new Surface({content: 'Footer'}),
        content: new Surface({content: 'Content'})
    }
});

Layout literals are implemented through LayoutHelpers. To create your own layout literals, perform the following steps:

  • Create a LayoutHelper (see LayoutDockHelper for an example).
  • Implement the parse function on the LayoutHelper.
  • Register the helper using LayoutUtility.registerHelper.

Layout helpers

Layout helpers are special classes that simplify writing layout functions.

Helper Literal Description
LayoutDockHelper dock Layout renderables using docking semantics.

Standard layouts

Layout DataSource Scrollable Description
ProportionalLayout LinkedListViewSequence / Array No Lays out renderables sequentially and sizes them proportionally.
HeaderFooterLayout Id-based No Layout containing a top-header, bottom- footer and content.
NavBarLayout Id-based No Layout containing one or more left and right items and a title.
TabBarLayout Id-based No Tab-bar layout.
Scrollable layouts:
ListLayout LinkedListViewSequence / Array Yes List layout with margins, spacing and optionally sticky headers.
CollectionLayout LinkedListViewSequence / Array Yes Lays out renderables in a grid with a specific width & height.
WheelLayout LinkedListViewSequence / Array Yes Lays out renderables in a wheel (slot-machine) formation.
CoverLayout LinkedListViewSequence / Array Yes Lays out renderables in a wheel (slot-machine) formation.

Documentation

Class Description
LayoutController Lays out renderables and optionally animates between layout states.
AnimationController Animating between famo.us views in awesome ways.
ScrollController Scrollable LayoutController (base class for FlexScrollView).
FlexScrollView Flexible scroll-view with pull-to-refresh, margins & spacing and more good stuff.
DatePicker Date/time picker wheel.
TabBar TabBar widget.
TabBarController TabBarController widget.
LayoutContext Context used for writing layout-functions.
LayoutUtility Utility class containing helper functions.
VirtualViewSequence Infinite view-sequence which uses a factory delegate to create renderables.
LinkedListViewSequence Linked-list based View-sequence which resolves various issues with the stock famo.us ViewSequence.

Contribute

If you like this project and want to support it, show some love and give it a star. Any donations are also very welcome and appreciated. To donate click here.

ยฉ 2014 - 2016 Hein Rutjes

famous-flex's People

Contributors

andrewreedy avatar gadicc avatar ijzerenhein avatar jeduan avatar nicholasareed avatar sidneys avatar stephanbijzitter avatar thaiat avatar tjclement avatar toostn avatar wheeler 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

famous-flex's Issues

scrollend not emitted from FlexScrollView when alwaysLayout is true

Hi,
I'm have been going nuts over the fact that scrollend is not being emitted. After debugging ScrollController for a while I resorted to trying weird things, and the moment I set autoLayout to false in my FlexScrollView's options, the event was being emitted again.

I tried turning it off and on and it certainly the factor that toggles this bug. Thing is, my app relies on both of these things working together :)
I tried looking into the calculations in ScrollController and my brain melted, so I'm just going to leave this as a bug report since I don't know how to fix this.

Thanks.

Rename ScrollView.js to avoid conflict with famo.us' own Scrollview.js

I recommend renaming the file ScrollView.js to FlexScrollView.js. When running webpack to package the javascript files it gives this warning that says it better than I do:

WARNING in ./~/famous/src/views/Scrollview.js
There is another module with an equal name when case is ignored.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Rename module if multiple modules are expected or use equal casing if one module is expected.

Support layout literals

Instead of declaring layout as a function, it is also practical to use a 'shorthand' notation in the form of layout-literals. This is useful for e.g. declaring autolayout constraints but also for docking principles:

var layoutController = new LayoutController({
  layout: {dock: [
    ['top', 'header', 50],
    ['bottom', 'footer', 50],
    ['fill': 'content']
  ]},
  dataSource: ...
});

Is there a way to use Famous Flex with Meteor Views?

Hello.

Is there a way to do something like this?

{{#ScrollController id="surfaceListScroll"}}
    {{#Surface}}SurfaceOne{{/Surface}}
    {{#Surface}}SurfaceTwo{{/Surface}}
    {{#Surface}}SurfaceThree{{/Surface}}
{{/ScrollController}}

Of course already did this:

FView.registerView('ScrollController', famous.flex.ScrollController);

It works good with default Scrollview.

The main question:
Is it possible to have dataSource property of ScrollController pointing on child elements in Render Tree?

Question: Intention with dataSource and alwaysLayout

The stock famo.us Scrollview automatically re-layouts the content as the view sequence/array set with sequenceFrom changes.

Is setting the alwaysLayout option of the LayoutController to true the recommended way to have the same behavior in the FlexScrollView, or would you recommend against this famo.us pattern? Is there another way, except for manually deleting/inserting surfaces with push/remove?

Support AutoLayout/cassowary constraints

Add support for Apple-style Autolayout / cassowary constraints.
The support shall be implemented as a LayoutHelper function and is not part of the core.
Additionally, layout-literals can be used to set constraints using a visual language:
https://developer.apple.com/Library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage/VisualFormatLanguage.html

var layoutController = new LayoutController({
  layout: {
    autoLayout: [
      'button(>=50)',
      '|-[find]-[findNext]-[findField(>=20)]-|'
    ]
  }.
  dataSource: ...
});

Angular Directive Will Be awsome

I'm very new to famo.us but I'm good in angularjs , can u please consider ,or guid me to build angular directives for your awsome controlles.

Combined & minified js

What's the recommended way to combine & minify the famous-flex source? When I require('famous-flex/FlexScrollView'), for example, the browser pulls 10 separate famous-flex files.

If there's interest and you (Hein) would like help with this, I can try my hand at writing a grunt build to create a single minified file.

Another advantage of a single source file is that it would be much easier to create live demos on jsfiddle, etc.

FlexScrollView ignores Z-translate

Hi there,
After our conversation at stackoverflow (http://stackoverflow.com/questions/28147595/z-translate-is-ignored-by-gridlayout-view) I did try to rewrite my code using FlexScrollView. Same result: in Chrome surface ignores z-translate and IE just shows black screen. Any ideas?

define(function(require, exports, module) {
var Engine = require("famous/core/Engine");
var Surface = require("famous/core/Surface");
var View = require("famous/core/View");
var ContainerSurface = require("famous/surfaces/ContainerSurface");
var StateModifier = require('famous/modifiers/StateModifier');
var Transform = require("famous/core/Transform");
var Utility = require("famous/utilities/Utility");
var Flex = require("famous-flex/src/FlexScrollView");
var CollectionLayout = require("famous-flex/src/layouts/CollectionLayout");

var mainContext = Engine.createContext();
    mainContext.setPerspective(1000);

var flex = new Flex({
    autoPipeEvents: true,
    mouseMove: true,
    direction: Utility.Direction.X
});

var cont1 = new ContainerSurface();
cont1.context.setPerspective(1000);
var surf1 = new Surface({size:[400, 200],properties:{background:'red'}})
var mod1 = new StateModifier();
cont1.add(mod1).add(surf1);

flex.push(cont1);
flex.push(new Surface({size:[400, 200],properties:{background:'green'}}));
flex.push(new Surface({size:[400, 200],properties:{background:'blue'}}));

Engine.on('click', function(){
    mod1.setTransform(Transform.translate(0,5,999), {duration:1000});
});
mainContext.add(flex);

});

Create scrollview/container

Create a scrollview/container solution which uses the layout-function for positioning renderables.
Feature support

  • true-size renderables (uses the size from the renderable)
  • good accessor functions for getting/setting the current position
  • switch scroll direction dynamically

ScrollView with GridLayout

Hello,

Can I just confirm that the new ScrollView using a GridLayout will not scroll? I want a [5,4] grid but I want to be able to scroll within that (or have a grid within a scoll). So if the screen can hold 20 grid cells based on the [5,4] dimensions and I have 120 cells, I want to be able to scroll to the other grid cells but keep the grid format.

Can ScrollView do this, or can you only scroll with the Collection and List Layouts?

Thanks again for all your help :)

Regards,
Mark

LayoutOptions cannot be changed using `setOptions` function

When an event occurs, I want to be able to change the layout options, but I seem to be unable to do so.
Calling FlexScrollView.setOptions({layoutOptions:{something:a}}) results in nothing being rendered, at all.

Right now I just want to change the itemSize in a CollectionLayout

Adding a ListLayout as child of a ListLayout

Hi, I tried to put a ListLayout within a ListLayout (I want to use a RenderController to show/hide a sub-list). Is this possible? So far I haven't succeeded. Here is a minimal example:

define(function(require, exports, module) {
    'use strict';

var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var LayoutController = require('famous-flex/LayoutController');
var ListLayout = require('famous-flex/layouts/ListLayout');

var mainContext = Engine.createContext();

var layoutController1 = new LayoutController({
    layout: ListLayout,
    flow: true,    
    direction: 1,  
    dataSource: [
        new Surface({content:"surface 1",size:[undefined,30]}),
        new Surface({content:"surface 2",size:[undefined,30]}),
        new Surface({content:"surface 3",size:[undefined,30]})
    ]
});     

var layoutController2 = new LayoutController({
    layout:ListLayout,
    flow:true,
    direction:1,
    dataSource: [
        new Surface({content:'the beginning',size:[undefined,30]}),
        layoutController1,
        new Surface({content:'the end',size:[undefined,30]})
    ]
});
mainContext.add(layoutController2);
});

The "the end" surface is not shown below "surface 3". Have I done something wrong, or is this a bug?

FlexScrollview cannot render true width surfaces correctly.

I am having trouble rendering surfaces with height and width set to [true,true] in the FlexScrollview. Basically, the width is getting confined to some max-width, even when I explicitly set a max-width that is larger. This is important because I am building a chat where the chat bubbles need to have a [true,true] size and a max-width that I specify. The image attached shows the behavior that is exhibited. The second image shows the same chatbubble code added to the DOM but not in the FlexScrollview.
screen shot 2014-12-28 at 12 18 23 am

screen shot 2014-12-26 at 9 20 48 pm

Browsified version

I saw a browsify section in the package.json.... is it possible to generate a browsified version of your lib?

Question / Request: Maybe a more complex demo.

How do you plan to integrate these layouts in a manner that allows for current standard responsive layouts. For instance intelligent removal and insertion of sections based on size availability or varying amounts of content in a section depending on space. Or something I finding annoying with famous, allowing a page to be scroll able in smaller screens but then when not in that layout allow it to be layed out completely differently without scroll on larger screens. Take this site fore example:

http://www.annestreetpartners.com.au/

It's a pretty standard responsive layout size with sections shrinking content changing and buttons appearing and disappearing depending on size at the time. I see the example and the set of pre-done layouts I'm just not sure on how to exert fine grain control or how these demos can integrate effectively into a layout that isn't as standard as the one we see in the demo. If my content isn't linear or all the same size.

Curious if you've seen any troubles with resize on page's with a large amount of content / processing going on. If you look at the angular famous's tiny demo on the famo.us page or John Traver site Frame.io both when you giggle the resize / just move it around a lot it will hang my browser for a little while.

What you have here is awesome hope it's just the start. It's way above my simple viewManager that manages the state and fires callbacks for different screensizes / debouces resizes so that it only happens after you stop moving the sizing.

Change proposal for useContainer

Currently it takes a boolean value and if true, it creates a new ContainerSurface instance to use as container. While this is good, I think it should take a truthy value instead:

false // dont use a container
true // use the default container (current behaviour)
someInstance // use this specific instance as container

This would make integration with my Famous Material package a bit easier, as it would allow the container to be styled by my package.

If you agree I'll work on it :)

Render true height View correctly

I have no problem adding true sized surfaces to the Flex ScrollView, however is there a way that I can create a true sized view that inherits the size from its child elements, so it can render correctly in a chat-like Flex ScrollView?

Embedded scrollview always fires both vertical & horizontal scrollstart

I implemented the Embedded scrollview scrolling restrictions that you decribed at
https://github.com/IjzerenHein/famous-flex/blob/master/tutorials/FlexScrollView.md#embedded-scrollview-scrolling-restrictions

Unexpectedly, it always fires both vertical & horizontal scrollstart events. I had to make a small change to work around that during vertical-only scrolling by setting a flag in the vertical scrollstart to prevent the horizontal scrollstart from coming in behind it and disabling the vertical. Logically it seems that setOptions({ enabled: false }) would disable the horizontal scrollstart firing, but there must be a race condition with the callbacks.

While the list is scrolling one way, it can't be scrolled the other way since it's waiting for the scrollend event to re-enable. This is problematic as the list decelerates and looks like it has stopped but not quite. Is there an option to increase the dampening effect?

Also is there an option to limit how far the list can be pulled away from the edge at the ends of the list? That inertia draws out how long the list continues moving and prevents swiping in the perpendicular direction. It would be great if that could be disabled because in my case, the horizontal scrollview shouldn't pull away from the edge.

Something really odd is happening with the scrolling

  • Desktop: no issue
  • iOS: ???
  • Android (4.4): scrolling is smooth if the finger used to scroll started on the image, but is not smooth if you start scrolling without your finger anywhere else.

Source: https://github.com/StephanBijzitter/Famous-Material-Examples
I also patched Scrollview.js with this PR (but it doesn't seem to change anything for this demo): johndoesenior/famous@6740e1d

I really don't understand what's going on and how this is happening, it makes no sense :'(

LayoutController is 1 pixel off <3

http://puu.sh/dqakQ.png

The surface shown:

        var surface = new Surface({
            properties : {
                outline : '1px solid green',
                border : '1px solid red',
                backgroundColor : 'white'
            }
        });
        layoutOptions : {
            itemSize : [undefined, 100],
            spacing : [0, 5],
            margins : [5, 0, 0, 0],
            justify : [0, 1]
        }

Outline is drawn around the element (and thus doesn't count towards its size).

Expected would be to see both red and green lines on the top and bottom, but only red lines on the left and right.

Setting the left margin to 1 [5, 0, 0, 1] makes the green outline on the left visible and hides the green outline on the right. This means that the width of the element is 1 pixel less than what its width should be.

I am unsure whether this is an issue with Famo.us or with Famous Flex, but I noticed it for the first time when expanding my examples.

After-effects functionality

Add ability to add one or more 'effects' to a layout-controller. An effect is a function which can modify the renderables after they have been layed-out. An effect-function will take in an EffectContext and is very similar to a layout-function. Effects can be added and removed, support transitions and a callback function:

var effectId = layoutController.addEffect(myRotationEffect, {duration: 100}, function () {
  console.log('effect has been applied');
});
layoutController.removeEffect(effectId, {duration: 100}, function () {
  console.log('effect has been undone');
});

LayoutController is unaware of size

    var footer = new LayoutController({
        layout : NavBarLayout,
        layoutOptions : {
            margins : 0,
            itemSpacer : 0
        },
        dataSource : {
            background : new Surface({
                size : [undefined, 80],
                properties : {
                    background : 'red'
                }
            })
        }
    });

    context.add(new Modifier({
        origin : [0.0, 1.0],
        align : [0.0, 1.0]
    })).add(footer);

This does not actually make the footer align to the bottom of the page, but to the top (as its height is unknown). (image: http://puu.sh/doIxm.png)

The following does work: (image: http://puu.sh/doIyf.png)

    context.add(new Modifier({
        size : [undefined, 80],
        origin : [0.0, 1.0],
        align : [0.0, 1.0]
    })).add(footer);

This happens because calling footer.getSize returns undefined when no modifier defines its size. It's not of a great priority to me in this case as I had to add a modifier either way to position the element, but if you just want to use context.add(component) you'd have to create a new modifier just to specify a size. A bit of a bummer.

But I must say that implementing your flex is really nice:
https://github.com/StephanBijzitter/Famous-Material-Examples

RenderNodes in dataSource instead of surfaces.

Hello IjzerenHein, and thank you for such great scrollview, it's really awesome!

But I have one little trouble.

I need to create listLayout from items.
Each item has 4 surfaces.

So each item is RenderNode.

Scrollview takes data from array, that contains all RenderNodes.

The problem is that scrollview in this case is not scrolling.

Here is some code:

var nodeSequence = new ViewSequence();

for(i = 0; i < 40; i++) {
    var surfaceOne = new Surface({
        size: [undefined, 50],
        content: 'one',
        properties: {
            backgroundColor: '#888'
        }
    });
    var surfaceTwo = new Surface({
        size: [undefined, 50],
        content: 'two',
        properties: {
            backgroundColor: '#222'
        }
    });
    var node = new RenderNode();
    node.add(surfaceOne).add(surfaceTwo);
    nodeSequence.push(node);
}

var myScroll = new ScrollController({
    layout: ListLayout,
    layoutOptions: {
        itemSize: 100
    },
    dataSource: nodeSequence,
    autoPipeEvents: true,
    mouseMove: true,
    debug: true
});

// I bult layout from modifiers, so layout node is from there.
layoutNode.add(myScroll);

It all works if nodeSequence contains surfaces.

So what I do wrong?
Is there a way to make list item that contains many surfaces?

Thank's.

PS
With default famous Scrollview it also doesn't work.

CollectionLayout justify is not working

http://puu.sh/esoVL.png
I'm trying to get my buttons in the horizontal center using [true, false], but regardless of what values I give, it doesn't do anything.

Note that this is on all browsers, and my android device.
I don't know if any recent update broke this or not, it's my first time using it.

Option to stop scrolling at the ends without temporary springy edge gap

As originally discussed in this thread, sometimes it would be better for the ends of the scrollview to stop at the edge instead of pulling away from it. The latter looks like how the "pull to refresh" works, where you can pull the list away from the edge and introduce a temporary gap before it snaps back. What I'd like to see is an option to not allow it to separate from the container edge (no temporary gap).

Please vote for this if you'd like this option too.

New RenderController size not recognized by LayoutController

Hi, I continued my experiments with the ListLayout and came upon a new problem, when I wanted to put a RenderController into a ListLayout. If the RenderController shows a surface, the LayoutController doesn't seem to recognize that something has changed. The getSize method of the RenderController doesn't seem to get called. The following would work with a SequentialList, but it doesn't work with a ListLayout:

define(function(require, exports, module) {
    'use strict';
    // import dependencies
    var Engine = require('famous/core/Engine');
    var Surface = require('famous/core/Surface');
    var RenderController = require('famous/views/RenderController');
    var LayoutController = require('famous-flex/LayoutController');
    var ListLayout = require('famous-flex/layouts/ListLayout');
    var mainContext = Engine.createContext();

    var middle = new Surface({content:"Hello World!",size:[undefined,40]});
    var renderController = new RenderController();
    renderController.active = false;
    renderController.getSize = function(){
        var size = middle.getSize();
        if(this.active)return size;
        else return [0,0];
    }.bind(renderController);
    var beginning = new Surface({content:"the beginning:",size:[undefined,true]});
    var end = new Surface({content:"the end.", size:[undefined,true]});
    var layoutController = new LayoutController({
        layout: ListLayout,
        size:[undefined,true],
        flow: true,    
        direction: 1,  
        dataSource: [beginning,renderController, end]
    });

    //clicking on the first surface toggles the surface that is "hidden" with the RenderController
    beginning.on("click",function(){
        if(!renderController.active)renderController.show(middle);
        else renderController.hide();
        renderController.active = !renderController.active;
    });
    mainContext.add(layoutController);
});

Animate item height in FlexScrollView

Hi,
I'm using FlexScrollView to display a list of items, I need the selected item (a state that my code is handling) to expand it's height.

I tried putting a StateModifier for my item's surfaces (all wrapped with a RenderNode), and animating it. It did work for the animation itself (although im only changing height via scale transform which stretches the content...), but the margin between other items does not change and they intersect. I also tried calling reflowLayout on the scrollview, it didn't seem to help (which makes sense since the item height isn't changing via transform).

So my question boils down to this:

  1. Is there a way for FlexScrollView to work good for item height animation?
  2. Is there a way to make a Surface taller without stretching it's content (aka not using transform to animate height)?

Thanks.

FlexScrollView expand items from center issue

Hi,
My app manages a state for items in FlexScrollView that causes an item to expand it's height.
This works fine just by putting RenderNodes with a StateModifier before the surface itself, and animating it's size.

UX people requested that I would make the item expand it's height from the center (bottom and top) instead of only from one edge. I tried using origin [0, 0.5] and the tranistion itself is done right, but it totally messes up the spacing between the items.

Online example: https://dl.dropboxusercontent.com/u/27964192/famous/index.html
This example just expands the items sequentially (reload to watch again).
Example without origin [0, 0.5], which is how the app is right now. https://dl.dropboxusercontent.com/u/27964192/famous/index2.html

Thanks.

NavBarLayout demo is broken

Given the following code:

        var context = Engine.createContext();

        var header = new LayoutController({
            layout : NavBarLayout,
            layoutOptions : {
                margins : [5, 5, 5, 5],
                itemSpacer : 10,
            },
            dataSource : {
                background : new Surface({
                    properties : {
                        background : 'red'
                    }
                }),
                title : new Surface({
                    content : 'My title'
                }),
                leftItems : [new Surface({
                    content : 'left1'
                })],
                rightItems : [new Surface({
                    content : 'right1'
                }), new Surface({
                    content : 'right2'
                })]
            }
        });

        context.add(new Modifier({
            size : [undefined, 48]
        })).add(header);

Taken from:
https://github.com/IjzerenHein/famous-flex/blob/master/src/layouts/NavBarLayout.js

The output:
http://puu.sh/dnozA.png

Fixed by:
Giving the left and right items a width (in this case [48, undefined]):
http://puu.sh/dnoD3.png

scroll and pageChange events from ScrollContainer

Hi! I really love the FlexScrollView you've made. It's soo much better than the stock famo.us scrollview!

One thing that could really help me, and likely others as well, is if the ScrollController could emit scroll events (any time the content offset is changed, not only when the user drags the content), in addition to the scrollStart and scrollEnd events already emitted.

It would also be great if it emitted the pageChange event in the same way the original famo.us scroll view does.

These events would make it easier to sync adjacent scroll views (e.g. as in the iOS task switcher), or to change e.g. a header text when a page changed.

Just some suggestions that would make your great component even better!

Regards,
Torsten

Multiple surfaces in FlexScrollView items sporadically change Z order

When the items in a FlexScrollView consist of multiple surfaces, scrolling them in and out of view causes their surfaces' Z order to change seemingly randomly. I observed this bug in Famo.us's stock Scrollview in their version 0.3.2. It's been fixed in 0.3.4 so perhaps that may offer some insight into this issue.

This self-contained code recreates it. The red box should be on top, the blue box just below it, and the red & green bars behind them both. Scroll all the way down, then all the way up. The red / blue boxes in some of the items drop below the other surfaces.

define(function(require, exports, module) {
    var Engine             = require('famous/core/Engine');
    var AppView            = require('views/AppView');
    var Surface            = require('famous/core/Surface');
    var ImageSurface       = require('famous/surfaces/ImageSurface');
    var StateModifier      = require('famous/modifiers/StateModifier');
    var RenderNode         = require('famous/core/RenderNode');
    var Transform          = require('famous/core/Transform');
    var FlexScrollView     = require('famous-flex/FlexScrollView');

    var mainContext = Engine.createContext();
    mainContext.setPerspective(1000);
    mainContext.setSize([300, 500]);

    this.scrollview = new FlexScrollView({
        // paginated: true,
        // mouseMove: true,
        layoutOptions: {
            //margins: [10, 5, 0, 15], 
            spacing: 2
        }
    });
    mainContext.add(this.scrollview);

    this.items = [];
    this.scrollview.sequenceFrom(this.items);
    this.size = [mainContext.getSize()[0], 200]

    for (var i=0; i<6; i++) {
        var itemModifier = new StateModifier({ size: this.size});
        var itemNode = new RenderNode(itemModifier);

        var background = new ImageSurface({
            size: this.size,
            properties: {
                backgroundColor: 'grey'
            },
            content: "https://famo.us/blog/wp-content/uploads/2014/12/19b.jpg"
        });
        background.pipe(this.scrollview);
        itemNode.add(background);

        var surface1 = new Surface({
            size: [this.size[0], 20],
            properties: {
                backgroundColor: 'yellow'
            }
        });
        surface1.pipe(this.scrollview);
        itemNode.add(surface1);

        var surface2 = new Surface({
            size: [this.size[0], 40],
            properties: {
                backgroundColor: 'green'
            }
        });
        surface2.state = new StateModifier({
            origin: [0, 1],
            align: [0, 1]
        });
        surface2.pipe(this.scrollview);
        itemNode.add(surface2.state).add(surface2);

        var surface3 = new Surface({
            size: [this.size[0]*0.5, this.size[1]*0.75],
            properties: {
                backgroundColor: 'blue'
            }
        });
        surface3.state = new StateModifier({
            origin: [0.5, 0],
            align: [0.5, 0.2]
        });
        surface3.pipe(this.scrollview);
        itemNode.add(surface3.state).add(surface3);

        var surface4 = new Surface({
            size: [this.size[0]*0.3, this.size[1]*0.3],
            properties: {
                backgroundColor: 'red'
            }
        });
        surface4.state = new StateModifier({
            origin: [0.5, 0],
            align: [0.5, 0.04]
        });
        surface4.pipe(this.scrollview);
        itemNode.add(surface4.state).add(surface4);


        this.items.push(itemNode);
    }

});

Keeping layout and functionality separate

Situation:
A NavBarLayout with 3 buttons and 1 title (like the example)
A button would have to inherit Surface.

Requirement:
I want to be able to change the options for each button with a single function and without specifying references to the buttons to change.

So my first thought was to add a function to NavBarLayout called NavBarLayout.setItemOptions(options). But that'd be a stupid move. LayoutController would seem a bit better, but still not a perfect fit as not all layouts contain items. And what if you would want to separate left and right items? Create a function for each?

So I figured I'd write up the next:

    LayoutController.prototype.setDataSourceOptions = function(options, identifier) {
        if (!Array.isArray(identifier)) {
            identifier = [identifier];
        }

        _forEachRenderable.call(this, function(renderable, key) {
            if (identifier.indexOf(key) <= -1) {
                return;
            }

            if (Array.isArray(renderable)) {
                for (var i = 0; i < renderable.length; i++) {
                    if (renderable.setOptions) {
                        renderable.setOptions(options);
                    }
                }
            } else if (renderable.setOptions) {
                renderable.setOptions(options);
            }
        }.bind(this));
    };

Usage example:

        header.setDataSourceOptions({
            properties : {
                color : 'red'
            }
        }, 'title');

This would be a bit of a middle ground solution, as no reference to the actual renderable needs to be provided: just its name/identifier/key. Currently this works for all layouts, but to make sure it's forward-compatible I'll quickly make this recursive and write up the documentation.

Any comment so far?

Licence

Hello,
Congratulation for your work, it will be very useful to the famo.us community !
I would like to use it in a commercial project and I don't see any licence.
Do you have any informations about this ?

Thank you !

Reflow on changes in viewsequence

Most of the core famous layouts can be used like this, where an javascript-array is the only needed part to add elements to it.

  var v = new XYZView();
  var seq = [];
  view.sequenceFrom(seq);

Later one can add/remove items to just the seq which the view reflows.

 seq.push( ... );

The FlexScrollView should also support this, maybe even detect re-orderings of items. Also for new items apply 'autoPipeEvents' behavior.

Master branch broke overflow hidden

        container: {
            overflow: 'hidden' // overflow mode when useContainer is enabled
        },

First of all, overflow isn't being applied because it needs to be:

        container: {
            properties: {
                overflow: 'hidden' // overflow mode when useContainer is enabled
            }
        },

That aside, when making that change, the scroller doesn't respond anymore, at all. Not to scroll events, nor click events, as if all pointer-events are ignored. But when inspecting the elements, pointer-events is set to auto (defined by famous-surface).

So perhaps the merging of options is going wrong then? I wasn't giving any custom ones, so I added container: {} to my options and surely enough it started scrolling again... but the overflow was forgotten.

Currently these are my options:

        useContainer : true,
        container : {
            attributes : {
                id : 'menu'
            }
        },

The id is applied, but the overflow is not (regardless of embedding it in properties)

I don't know what's going on here :(

Scroll events are always emitted in first commit call

Since this._scrollOffsetCacheis undefined in first commit, the ScrollController always emits all scroll events as it is added to the render tree. To me, this seems unintentional.

Perhaps checking this._scrollOffsetCacheagainst undefined will fix the issue, or should it have a default value of 0 set in the constructor?

Auto ReflowLayout on node size change?

First let me say that what you have done so far is awesome. This fits very well into what I've already been doing, and you have made a great framework out of it.

I have some nodes/views that determine their size dynamically, and that size can change over time. If I use/build a layout that uses 'true' sized nodes, such as with NavBar, it lays them out initially, but if their size changes, it does not re-layout (size is not requested again until reflow). If I detect the change and call reflowLayout(), that works, but is pretty messy and breaks a lot of abstractions.

What do you think about adding (maybe as an option, so it can be turned off if not needed) a check (with a cache) to see if any of the current targets have changed size? If any have, then it would auto reflow.

CollectionLayout `direction` value reversed?

Ok, it's only my 3rd day with famous-flex so hope I'm not doing anything stupid :) But the direction (which I'm applying directly to FlexScrollView and not via layoutOptions) seems to have the opposite behaviour I'd expect - but only for CollectionLayout.

It's a bit harder to tell in the famous-flex demo, where you only see the icon and not the current direction, but if you look at http://fview-flex.meteor.com/ where we map direction via Utilities.Direction[key], with direction="X" it lays out the renderables vertically, and with direction="Y" it does so horizontally, which seems counter-intuitive.

I did just realize that in this case the direction does actually represent the way the scrollview will scroll, and maybe that was your intention. It's a bit confusing though. If you cycle through all the different layouts, all the items are ordered "intuitively" except for this one. Thoughts?

Using the 'moveMove' option causes click events to be fired when scrolling

TLDR: If dragged the scrollview should consume/destroy the click event to make sure that the onClick handler of the renderable that was dragged is not activated.

You should set a threshold, as most people will move the mouse a few pixels between press and release (while still being a click), so I'd suggest the following:

If the user drags the mouse to scroll and scrolls at least 1 index, the onClick handler should not be activated.

Original issue on Famous: Famous/famous#211

Explain how LayoutController places surfaces

Adding an extra "More" button to the left of input field was easy. Even without documentation that explains how 'fill' and 'bottom' works.

flex-chat

messageBar = new LayoutController({
        layout: {dock: [
            ['fill', 'back'],
            ['left', undefined, 8],
            ['top', undefined, 8],
            ['right', undefined, 8],
            ['bottom', undefined, 8],
            ['left', 'moreButton', undefined, 1], /* Add the more button... */
            ['right', 'send', undefined, 1],
            ['fill', 'input', 1]

What I haven't managed to figure out is how to add an extra box below the input bar. Here's an example that shows briefly what I want to accomplish.

screen568x568

I like the idea of extending famo.us with a more flexible layout manager. Ultimately I think many developers want all the examples, widgets and examples that Ionic has but with the speed and possibilities that comes with famo.us.

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.