gadicc / meteor-famous-views

Famous, the Meteor Way (with Reactive Blaze Templates/Views)
http://famous-views.meteor.com/
GNU Lesser General Public License v3.0
332 stars 27 forks source link

Scrollview weird flicker/wobble #210

Open krishnaff opened 9 years ago

krishnaff commented 9 years ago

Hello,

Whenever the elements in the Scrollview change reactively, it bounces and shifts position (if the resultant list is shorter than the previous). I captured a short video - http://youtu.be/sjGS9Brybi8 Please take a quick look! :) Especially notice the shift when All Games filter changes to Cricket.

The code I have is pretty straightforward:

{{#View size="[undefined,undefined]"}}
    {{#Scrollview size="[undefined,undefined]" translate="[0,10,101]"}}

        {{#Surface size="[undefined,50]" class=""}} 
            {{>filterTemplate}}
        {{/Surface}}

        {{#famousEach gamesList}}
            {{#Surface size="[undefined,90]" class=""}}
                <html for showing name, title, date etc>
                    {{/Surface}}
        {{/famousEach}}

    {{/Scrollview}}
{{/View}}

<template name="filterTemplate">
    <select class="picker">
      <option value="all">All Games</option>
      <option value="Cricket">Cricket</option>
      <option value="Soccer">Soccer</option>
      <option value="Tennis">Tennis</option>
      <option value="Golf">Golf</option>
        ....
    </select>
</template>

Event and Helper:

Template.filterTemplate.events({
    'change': function(e, template) {
        Session.set('gameFilter', e.target.value);    
        }
})

Template.livenow.helpers({
    gamesList: function() {
        if (Session.get('gameFilter') === 'all' || Session.get('gameFilter') === undefined) {
            return Games.find({}, {sort: {"gameType": 1} });
        } else {
            return Games.find({"gameType": Session.get('gameFilter')}, {sort: {"gameType": 1} });      
        }
    }
})

Please note that when the data changes from the server, the scrollview works perfectly. For example, if there are 25 games published from the server, and this becomes 27 (5 adds, 3 removals), the scrollview updates perfectly without any glitches. So the problem occurs when the static filter is used. For example: 25(all games) switches to 4(cricket) for example. If the list is sufficiently long, then it works fine as you can see in the video.

I did try out watchSize and _contentDirty = true, but I'm guessing these work on surfaces and not on the entire Scrollview.

Is there something very obvious I'm missing? Your help/suggestions would be greatly appreciated! Thanks.

Wenape commented 9 years ago

This same issue happens to me when modifying the data context (Session variable) for a Scrollview. Maybe applying an override on the famousEach view to recalculate the size of the Scrollview could work, but I'm not really sure.

krishnaff commented 9 years ago

Hi @Wenape How do we apply an override on the famousEach? Could you give an example please?

Are you referring to the _contentDirty=true or watchSize=true? I also tried setting an actual size (ex: [undefined, 90 * x], where 'x' is the number of elements inside scrollview) via template helpers for the scrollview, but that didn't help either.

Looking at the log, I'm thinking the child surface destroys and addition of new surfaces happening simultaneously is causing some sort of problem? Anyway, please let me know if you get it working. Thanks!

gadicc commented 9 years ago

Hey all, seems to be a Famous bug. I made a small reproduction below where you can see the same effect. You can run locally or copy and paste into Famo.us university:

var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var Modifier = require('famous/core/Modifier');
var Scrollview = require('famous/views/Scrollview');

var mainContext = Engine.createContext();
var modifier = new Modifier({size: [undefined,undefined]});
scrollview = new Scrollview();

var allSurfaces = [];

window.update = function(num) {
  surfaces.splice(0, surfaces.length);
  for (var i=0; i < num; i++)
    surfaces.push(allSurfaces[i]);
}

var header = new Surface({
    content: "<button onclick='update(5)'>5</button>" +
      "<button onclick='update(15)'>15</button>" +
      "<button onclick='update(30)'>30</button>",
    size: [undefined, 50],
    properties: {
        backgroundColor: 'white',
        color: "black",
        lineHeight: '50px',
        textAlign: 'center'
    }  
});

for(var i = 0; i < 30; i++) {
  allSurfaces.push(new Surface({
      content: "panel " + (i + 1),
      size: [undefined, 50],
      properties: {
          backgroundColor: "hsl(" + (i * 360 / 30) + ", 100%, 50%)",
          color: "#404040",
          lineHeight: '50px',
          textAlign: 'center'
      }
  }));
}

surfaces = [];
for (var i=0; i < allSurfaces.length; i++)
  surfaces.push(allSurfaces[i]);

scrollview.sequenceFrom(surfaces);
mainContext.add(modifier).add(scrollview);
mainContext.add(header);
Engine.pipe(scrollview);

Will comment on some other stuff in the next post.

gadicc commented 9 years ago

@insaneinc01, yeah, those attributes you mentioned are only for Surfaces. @Wenape, you don't need to manually update the Scrollview size... the size of the scrollview itself (say outerHeight in HTML terms) is the size parameter (how much space it takes up on the screen), but then it's "scrollHeight" (in HTML terms, i.e. the height of it's inner contents) is recalculated on every redraw (60fps), using the size of every Surface/renderable in the array. There just seems to be a positioning issue when that total height is less than the view height, when it wasn't before. Would be great if someone can scan through issues on Famo.us repo, see if there's an open issue for it otherwise open a new issue, and link back here :)

gadicc commented 9 years ago

Oh also the "famousEach overrides" is a new feature since v0.1.31; you can read about it at the bottom of http://famous-views.meteor.com/features/api (under the "Events" heading). It's unlikely you'd ever need it at the application level though, more useful for wrapping more advanced Views.

Wenape commented 9 years ago

This issue https://github.com/Famous/famous/issues/506 addresses most recent problems and bugs regarding the Scrollview. These have probably been arising recently as more people develop complex apps which mix rich functionality with different views.

I guess the only solution for now is using different workarounds for these bugs. For this case in particular, it could help trying to control the position of the Scrollview before it goes nuts. The only solution I can think of right now is to hook to the update event of the Scrollview and watch any weird _displacement values, then set the appropiate position with .setPosition(). There is a chance this could cause flickering though. I'll try to test it and see.

gadicc commented 9 years ago

@insaneinc01, @Wenape - also, depending on your exact requirements, using the new fview-flex might also be an option. it's a very early release, but the ListLayout might serve your purposes. It does support true-sized Surfaces... in a future version of both that and famous-views I'll make sure that watchSize propagates up and updates the view; for now you can use alwaysLayout: true in the FlexScrollView.