tuning app UI (e.g. carousel)

edited June 2012 in Enyo 1.0
I'm coming to end of my 1.0 release (using enyo 1.0 on Android with PhoneGap) and I have a very uneasy feeling about it. The performance is keeping me up at night (and that's based on what I see on my Galaxy Nexus -- what are the more modest devices gonna do?). It's not a huge app, in fact all the data is really simple.

I've got a carousel of views that is painfully slow to flick through. I've looked through forum posts to find a solution. I've found the code in the Scrolling ... post that fixes the dragging in ScrollStrategy. I don't think that will help (tried it). Is there any other known issues around carousels?

The other real annoyance is that when I'm flicking through the carousel, it doesn't animate the rest of the flick after I lift my finger up. That makes it really hard to detect visually whether or not it actually went to the next/prev view. Is there any fix for that?

The UI was fun to create - really easy to assemble. But these issues have got to be fixed before I ship this thing.

Comments

  • I have been working with the scrollers on enyo 1 to try and smooth it out on the phones and the system popup window on the touchpad. I have got it going pretty damn well but havnt tested it on android yet.
    I will post the code I have changed when I get home from work in a couple hours and you can try it out then.
  • OK, here is the code:

    https://github.com/appsbychris/enyo1scroller/blob/master/customscroller.js

    I have it as its own JS file. I use a global variable (ISPHONE) in my app to adjust the scrolling on the phone vs touchpad.

    Then you just replace your kind's with the Custom kinds.

    Let me know how it goes. I am going to make the app i use this in run on android in the next month or so.
  • Thanks chris. I'm using a VirtualCarousel so I copied VirtualCarousel into a new CustomVirtualCarousel and changed it to be a CustomCarouselInternal kind. Unfortunately, I don't really see any difference on my phone.

    To me, the biggest issue is how slowly it responds to my initial swiping motion. Native controls respond pretty much immediately. I know that's a high bar to set, but that's what I'm going to be judged against.

    The other biggie is the animation when dragging is done. I don't see any. It just snaps immediately. Would that be smoother in code or with a CSS transition?
  • have you tried setting accelerated to false in the scroller?
    I would go through the scroller code and tweak some of the variables and see what results it makes.
  • @cookie Unfortunately, both enyo and webos were optimized to work fine together (specially scrolling). I wonder why you didn't moved to Enyo2.
  • edited June 2012
    @rafa_bernard I've been so heads down on getting functionality in that I haven't been keeping up with Enyo2. The website says that if I know Enyo1 I'll be right at home with Enyo2. Given that, I've been assuming that it won't be very hard to migrate.
    Last time I checked, Enyo2 was short on controls (no Panel, Carousel, Repeater, VirtualList, etc.). Maybe I'm missing something. Should I even be looking for the same controls or will they all have changed? Or does Enyo2 just replace base classes? I guess I'm not sure how to know when is a good time to invest the time to migrate.
  • With the latest additions to the layout and onyx libraries, you now have most of the controls.

    The layout library provides panels and list, enyo.Repeater is in the base UI code, and you can do a carousel using the arrangers in the panels code.
  • The main barrier I'm seeing so far is the absence of webkit-dependent controls which are used widely in most webOS applications. I've started work on a support library for redeploying webOS ( and, in general, enyo 1) apps on webkit platforms using enyo 2 but it's not solid enough to share quite yet.
  • Note, the main webkit-reliant part, IIRC, are the flexbox controls. The whole flexbox spec is in flux right now, with the latest working draft, http://www.w3.org/TR/css3-flexbox/, a bit different than what was implemented in the WebKit on the TouchPad. There's a changes section in that document showing what's been updated. I've not tried to tackle the question of cross-browser compatibility with that yet.
  • Most of the work I've done has been just recreating the flexlayout/box material in enyo 1. I've also put together some custom controls that use -webkit-animations and -transitions which looked great on webOS, and I've had good results so far. Some of them work cross-browser, but others need work or simply fall back to instant transitions.

    Some of those changes to the draft are kind of vague... Guess I'll just have to wait and see what happens and react accordingly.
  • @omastudios that sounds like something everybody would need. I use them religiously throughout my app. Without flex layouts, what would I use in Enyo2?
    In general it sounds like migrating would be a hefty task for me. Converting flex layouts/boxes to something else. Carousels are now arrangers. Repeater has moved (changed API?). Is there any help for this anywhere? Blog post maybe?
  • edited June 2012
    maybe this can help. It shoud work with enyo 2:

    enyo.kind({
    name: "enyo.FlexLayout",
    kind: "Layout",
    //* Set to one of "start", "center", "end", or "justify"
    pack: "start",
    //* Set to one of "start", "center", "end", "baseline", "stretch"
    align: "stretch",
    constructor: function(inContainer) {
    // FIXME: not ideal
    this.prefix = enyo.isMoz ? "-moz" : "-webkit";
    if (inContainer) {
    // propagate settings from the container
    // TODO: containers should have layoutProps bag to support
    // arbitrary layouts. Certain extremely common layout options
    // (namely flex, pack, align) can be published as high level
    // properties that virtualize eponymous layoutProps.
    // Currently, we are simply reading these properties directly.
    this.pack = inContainer.pack || this.pack;
    this.align = inContainer.align || this.align;
    }
    this.container = inContainer;
    this.inherited(arguments);
    },
    destroy: function() {
    if (this.container) {
    delete this.container.setFlex;
    this.container.removeClass(this.flexClass);
    }
    },
    //* @protected
    calcFitIndex: function() {
    for (var i=0, c$=this.container.children, c; c=c$[i]; i++) {
    if (c.fit && c.showing) {
    return i;
    }
    }
    },
    getFitControl: function() {
    var c$=this.container.children;
    var f = c$[this.fitIndex];
    if (!(f && f.fit && f.showing)) {
    this.fitIndex = this.calcFitIndex();
    f = c$[this.fitIndex];
    }
    return f;
    },
    getLastControl: function() {
    var c$=this.container.children;
    var i = c$.length-1;
    var c = c$[i];
    while ((c=c$[i]) && !c.showing) {
    i--;
    }
    return c;
    },
    calcControlFlex: function(inControl, inExtent, inExtentNick) {
    //console.log(inControl)
    var s = inControl.domStyles;
    if (inControl.flex) {
    return inControl.flex;
    } else if (s[inExtent] == "100%" || inControl[inExtentNick] =="fill") {
    delete s[inExtent];
    return (inControl.flex = 1);
    }
    return null;
    },
    flowExtent: function(inControls, inExtent, inExtentNick) {

    for (var i=0, c, s, f; (c=inControls[i]); i++) {
    f = this.calcControlFlex(c, inExtent, inExtentNick);
    s = c.domStyles;
    s[this.prefix + "-box-flex"] = f;
    if (f) {
    // we redefine flex to mean 'be exactly the left over space'
    // as opposed to 'natural size plus the left over space'
    if (!s[inExtent]) {
    s[inExtent] = "0px";
    }
    // Mozilla doesn't seem to 'stretch' correctly on this axis
    if (enyo.isMoz && inExtent == "height" && this.align == "stretch") {
    s.width = "100%";
    }
    }
    c.applyStyle(s);
    //console.log(s)
    }

    },
    reflow: function(measure, cMeasure, mAttr, nAttr) {
    inContainer=this.container;
    var s = inContainer.domStyles;
    //s[this.prefix + "-box-pack"] = inContainer.pack || this.pack;
    //s[this.prefix + "-box-align"] = inContainer.align || this.align;
    inContainer.applyStyle(this.prefix + "-box-pack",inContainer.pack || this.pack);
    inContainer.applyStyle(this.prefix + "-box-align",inContainer.align || this.align);
    inContainer.addClass(this.flexClass);
    //console.log(inContainer.children)
    this._reflow(inContainer.children);


    statics: {
    _ieCssToPixelValue: function(inNode, inValue) {
    var v = inValue;
    // From the awesome hack by Dean Edwards
    // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
    var s = inNode.style;
    // store style and runtime style values
    var l = s.left;
    var rl = inNode.runtimeStyle && inNode.runtimeStyle.left;
    // then put current style in runtime style.
    if (rl) {
    inNode.runtimeStyle.left = inNode.currentStyle.left;
    }
    // apply given value and measure its pixel value
    s.left = v;
    v = s.pixelLeft;
    // finally restore previous state
    s.left = l;
    if (rl) {
    s.runtimeStyle.left = rl;
    }
    return v;
    },
    _pxMatch: /px/i,
    getComputedStyleValue: function(inNode, inProp, inComputedStyle) {
    var s = inComputedStyle || enyo.dom.getComputedStyle(inNode);
    if (s) {
    return parseInt(s.getPropertyValue(inProp));
    } else if (inNode && inNode.currentStyle) {
    var v = inNode.currentStyle[inProp];
    if (!v.match(this._pxMatch)) {
    v = this._ieCssToPixelValue(inNode, v);
    }
    return parseInt(v);
    }
    return 0;
    },
    calcBoxExtents: function(inNode, inBox) {
    var s = enyo.dom.getComputedStyle(inNode);
    return {
    top: this.getComputedStyleValue(inNode, inBox + "-top", s),
    right: this.getComputedStyleValue(inNode, inBox + "-right", s),
    bottom: this.getComputedStyleValue(inNode, inBox + "-bottom", s),
    left: this.getComputedStyleValue(inNode, inBox + "-left", s)
    };
    },
    //* Get the calculated padding of a node
    calcPaddingExtents: function(inNode) {
    return this.calcBoxExtents(inNode, "padding");
    },
    //* Get the calculated margin of a node
    calcMarginExtents: function(inNode) {
    return this.calcBoxExtents(inNode, "margin");
    }
    }
    });

    enyo.kind({
    name: "enyo.HFlexLayout",
    kind: "FlexLayout",
    orient: "h",
    flexClass: "enyo-hflexbox",
    _reflow: function(inControls) {
    this.flowExtent(inControls, "width", "w");
    },
    });

    enyo.kind({
    name: "enyo.VFlexLayout",
    kind: "FlexLayout",
    flexClass: "enyo-vflexbox",
    orient: "v",
    _reflow: function(inControls) {
    this.flowExtent(inControls, "height", "h");
    },
    });

    enyo.kind({
    name: "enyo.VFlexBox",
    layoutKind: "VFlexLayout",
    /** By default items in columns stretch to fit horizontally; set to false to avoid this. */
    //noStretch: false
    });

    enyo.kind({
    name: "enyo.HFlexBox",
    layoutKind: "HFlexLayout",
    /** By default items in columns stretch to fit vertically; set to false to avoid this. */
    //noStretch: false
    });
  • Can you please use gist.github.com or jsfiddle.net for long posts like this? Seeing huge chunks of code in threads is rarely useful.
  • I actually went for a grounds-up approach using a base FlexBox control kind rather than creating a Layout to be applied to controls, but the code still looks pretty useful. Do you mind it being reused? I'm guessing a large chunk comes from enyo 1 anyway (from what I can tell).
  • Yes it is Enyo 1. Adapted to work with Enyo 2(beta 4 not tested with beta 5). Of course its meant to be reuse!
    @unwiredben: sorry will do next time
  • @cookie I'll be sharing a dynamic carousel this weekend (we're orphans of it right now). Hope it helps in your transition.
Sign In or Register to comment.