Showing posts with label scroll. Show all posts
Showing posts with label scroll. Show all posts

Wednesday, May 23, 2018

Ipad Safari - Can't scroll page if scrolling inside iframe

Leave a Comment

Is it possible to continue scrolling through a webpage even if you are touching inside an iframe? This problem only happens with iOS devices and I couldn't find any solutions for this!

My current page contains an iframe in the middle with width:95% and about 500px height, so when I reach the iframe I can't scroll any more (unless I touch very close to the sides).

Thanks

2 Answers

Answers 1

In my case, I had full access to the iframe and was dynamically inserting its content. Still, none of the solutions suggested by Brandon S worked. My solution:

  • Create a transparent div overlaying the iframe.
  • Capture any click events on the overlay and replicate them within the iframe (to allow the user to click on links/buttons)

This works because the overlaying div is part of the outer document, making it respond to touch/click events normally, and prevents the user from directly interacting with the iframe content.


Html Template:

<div style="position: relative;">     <div         style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; opacity: 0;"         ng-click="$ctrl.handleOverlayClick($event)"     ></div> </div> 

Controller (AngularJS component)

...  constructor ($document, $element) {   this.iframe = $document[0].createElement('iframe');   this.iframe.width = '100%';   this.iframe.height = '100';   this.iframe.sandbox = 'allow-same-origin allow-scripts allow-popups allow-forms allow-top-navigation';   const element = $element[0].children.item(0);   element.appendChild(this.iframe);   this.contentDocument = this.iframe.contentDocument; }  handleOverlayClick ($event) {   // Overlay element is an invisible layer on top of the iframe. We use this to   // capture scroll events which would be in the iframe (which don't work properly on iPad Safari)   // When a click is detected, we propigate that through to the iframe so the user can click on links   const rect = $event.target.getBoundingClientRect();   const x = $event.clientX - rect.left; // x position within the iframe   const y = $event.clientY - rect.top;  // y position within the iframe    // triggering click on underlaying element   const clickedElement = this.contentDocument.elementFromPoint(x, y);   clickedElement && clickedElement.click(); } 

Answers 2

It sounds like the iframe is receiving the user's scroll event, instead of the page. This can happen when part of the iframe's content doesn't fit within the size of the iframe element.

A solution to this problem is to stop the iframe from ever trying to scroll. There are few ways to accomplish this:

  1. In iframe's HTML, add this CSS:
     html, body {         overflow: hidden     }  
  1. If you don't have access to the iframe's HTML (because maybe the iframe is loading a 3rd party's content), you can put a wrapper div around the iframe and disable scrolling that way. Add this to the parent page HTML:

    <div style="overflow: hidden"><iframe src="example.com"></iframe></div>

  2. You can add this to the parent page HTML CSS to make browser use momentum so that ends up scrolling past the bottom of the iframe and then scrolls the page:

    *{         -webkit-overflow-scrolling: touch     }  
  1. Add the legacy "scrolling" attribute to the iframe to stop the iframe from trying to scroll:

    <iframe src="example.com" scrolling="no"></iframe>

Read More

Monday, May 7, 2018

Scroll not working with shorter text untill you flip iphone

Leave a Comment

Basically the issue can be viewed here, I blurred it on purpose, but the issue is easily visible. https://i.gyazo.com/f9a4fa72d35165acbeea94b71a15eaa6.mp4

I've got this weird issue that only appears on iphone, if there is only 1 message present, and that element is overflowing, it just won't add the scrollbar to the container. Untill I flip my phone to landscape and then back to the original state. After that it's perfectly scrollable. Other conversations are working fine that have more than one message. This issue both occurs on chrome and safari on iPhone.

The css for the container is quite simple.

.container {    width: 320px;     overflow-y: scroll; } 

The css for the messages inside are simple too, they only have a fixed width, no height specified.

If I check on Chrome and simulate as iphone on my desktop, it works fine too.

Does anybody know how I can fix this issue?

1 Answers

Answers 1

It would seem that your container isn't initially scrolling because the content does not extend beyond the height of the container. This changes when you rotate the screen because the content then extends beyond the screen height. You may want to try defining a min-height on an inner container that's greater than the displayable height.

.container {    /* Define height for container, probably best to use calc with a vh to dynamically assign for various screen heights. */    height: 800px;    overflow-y: scroll;    /* Utilize a dynamic width to fit variable screen widths. */    width: 100vw;  }    .container--inner {    /* The extra percent should force scrolling. */    min-height: 101%;  }
<div class="container">    <ul class="container--inner">      <li class="entry>...</li>    </ul>  </div>

Read More

Saturday, February 10, 2018

Unable to create scrollable area inside a scrollable area on ios

Leave a Comment

The following code works fine on desktop and android mobile however it does not work on ios. I would appreciate any help to get me in the right direction.

https://jsfiddle.net/slash197/047c4dj8/6/

html, body {     width: 100%;     height: 100%;     margin: 0px;     padding: 0px; } .holder {     position: relative;     width: 100%;     height: 100%;     overflow-y: scroll;     overflow-x: hidden;     -webkit-overflow-scrolling: touch; } .content {     width: 100%;     height: 128px;     overflow-y: hidden;     overflow-x: scroll;     -webkit-overflow-scrolling: touch; } .row {     width: 3000px;     height: 100%;     background-image: -webkit-linear-gradient(         left,         rgba(0, 0, 255, 0.0)   0%,         rgba(0, 0, 255, 1.0) 100%     ); }   <div class="holder">     <div class="content">         <div class="row"></div>     </div>     <div class="content">         <div class="row"></div>     </div>     <div class="content">         <div class="row"></div>     </div>     <div class="content">         <div class="row"></div>     </div>     <div class="content">         <div class="row"></div>     </div>     <div class="content">         <div class="row"></div>     </div> </div> 

2 Answers

Answers 1

IOS Safari is ignoring the width in percentage change it into px and it will start working check the fiddel link below.

    <!DOCTYPE html> <html>     <head>         <style>             html, body {                 width: 100%;                 height: 100%;                 margin: 0px;                 padding: 0px;             }             .holder {                 position: relative;                 width: 1000px;                 height: 100%;                 overflow-y: scroll;                 overflow-x: hidden;        -webkit-overflow-scrolling-x: touch !important;             }             .content {                 width: 1000px;                 height: 128px;         display:block;         float:left;                 overflow-y: hidden;                 overflow-x: scroll;         -webkit-overflow-scrolling-x: touch !important;             }             .row {                 width: 3000px;                 height: 100px;         display:block;         float:left;                 background-image: -webkit-linear-gradient(                     left,                     rgba(0, 0, 255, 0.0)   0%,                     rgba(0, 0, 255, 1.0) 100%                 );             }         </style>     </head>     <body>         <div class="holder">             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>             <div class="content">                 <div class="row"></div>             </div>         </div>     </body> </html> 

https://jsfiddle.net/pe6t29kf/11/

Answers 2

I noticed in your listed code you set the .row class with a pre-defined width, thereby ensuring every <div> element with that class will require a scroll. I'm assuming it's the horizontal scroll that fails, correct? I don't have an iPhone, but I noticed someone mentioned that the above code works in iOS. Is it possible that in the actual code the content requiring a horizontal scroll is dynamically generated?

If so, have you tried to force the content to always be marked to scroll, similar to what you did above, by setting a fixed width or min-width property, possibly to a percentage > 100%?

<div class="holder">     <div class="content">         <div class="row" style="min-width: 101%"></div>     </div> </div> 

I'm not an expert on iOS, but if it involves dynamically generated content, it's possible the problem could be an iOS scrolling quirk related to this issue.

iOS 9 `-webkit-overflow-scrolling:touch` and `overflow: scroll` breaks scrolling capability

Read More

Sunday, December 24, 2017

Move table footer to bottom of scrolling div dynamically using jquery

Leave a Comment

I have a scenario in which I have to move table footer row's each th tag at the bottom of scrolling div. Here is the plnkr.

I can move it hardcoded by

$('.sticky-table').find("table tfoot tr.sticky-row th").css('top', 260); 

but i want to calculate 260 and do it. Need help.

2 Answers

Answers 1

You need to calculate the bottom position of the whole container and subtract the height of the horizontal scrollbar from it. It will get you the top position of the footer row th elements.

$('.sticky-table.sticky-headers').offset().top //top of the container + $('.sticky-table.sticky-headers').outerHeight() //height of the container (adding it with top gives you the bottom position of the container) - $('.sticky-table').find("table tfoot tr.sticky-row th").outerHeight(true) //height of the footer headers - 11 //Fixed height of the scrollbar 

Created the updated plunker.

Answers 2

This can be achieved with a few simple lines of CSS. This eliminates the need to do complex calculations based on heights and positions in jQuery, and has the added benefit of being responsive, if needed.

The goal is to absolutely position the tfoot element at the bottom of the .sticky-table element.

To do this, we can give the .sticky-table a position: relative;, and the tfoot a position: absolute; bottom: 0;.

.sticky-table {   /* ...existing styles */   position: relative; }  .sticky-table tfoot {   position: absolute;   bottom: 0; }     

Like this:

/* Styles go here */    .sticky-table {    position: relative;    max-width: 100%;    max-height: 500px;    height: 500px;    overflow: auto;    border-top: 1px solid #ddd;    border-bottom: 1px solid #ddd;    padding: 0 !important;  }    .sticky-table table {    margin-bottom: 0;    width: 100%;    max-width: 100%;    border-spacing: 0;  }    .sticky-table table tr.sticky-row th,  .sticky-table table tr.sticky-row td {    background-color: #fff;    border-top: 0;    position: relative;    outline: 1px solid #ddd;    z-index: 5;  }    .sticky-table table td.sticky-cell,  .sticky-table table th.sticky-cell {    background-color: #fff;    outline: 1px solid #ddd;    position: relative;    z-index: 10;  }    .sticky-table table tr.sticky-row td.sticky-cell,  .sticky-table table tr.sticky-row th.sticky-cell {    z-index: 15;  }    .sticky-table tfoot {    position: absolute;    bottom: 0;  }    .sticky-table::-webkit-scrollbar {    width: 0.7em;    height: 0.7em;  }    .sticky-table::-webkit-scrollbar-track {    -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);  }    .sticky-table::-webkit-scrollbar-thumb {    background-color: #b37e7e;    outline: 1px solid slategrey;    border-radius: 5px;  }
<div class="row">    <div class="col-md-12">      <div class="sticky-table sticky-headers">        <table class="table table-striped table-striped">          <thead>            <tr class="sticky-row">              <th>Campaign Name</th>              <th>Ad Sets</th>              <th>Ads</th>              <th>Blue</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              </tr>          </thead>          <tbody>            <tr>              <td class="sticky-cell">Demo Campaign</td>              <td class="sticky-cell">100</td>              <td class="sticky-cell">200</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>            </tr>            <tr>              <td class="sticky-cell">Demo Campaign</td>              <td class="sticky-cell">100</td>              <td class="sticky-cell">200</td>              <td>Blue</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              <td>2000</td>              <td>Ford</td>              <td>Escort</td>              <td>Blue</td>              <td>2000</td>              </tr>          </tbody>          <tfoot>            <tr class="sticky-row">              <th class="sticky-cell">Demo Campaign</th>              <th class="sticky-cell">100</th>              <th class="sticky-cell">200</th>              <th>Blue</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              <th>2000</th>              <th>Ford</th>              <th>Escort</th>              <th>Blue</th>              <th>2000</th>              </tr>          </tfoot>        </table>      </div>    </div>    </div>

Read More

Sunday, November 26, 2017

Changing CSS transform on scroll: jerky movement vs. smooth movement

Leave a Comment

I'm dissatisfied with existing parallax libraries, so I'm trying to write my own. My current one consists of three main classes:

  • ScrollDetector tracks an element's scroll position relative to the screen; it has functions to return a float representing its current position:
    • 0 represents the top edge of the element being at the bottom edge of the viewport
    • 1 represents the bottom edge of the element being at the top edge of the viewport
    • All other positions are interpolated/extrapolated linearly.
  • ScrollAnimation uses a ScrollDetector instance to interpolate arbitrary CSS values on another element, based on the ScrollDetector element.
  • ParallaxativeAnimation extends ScrollAnimation for the special case of a background image that should scroll at a precise factor of the window scroll speed.

My current situation is this:

  • ScrollAnimations using transform: translateY(x) work smoothly.
  • ParallaxativeAnimations using translateY(x) work, but animate jerkily.
  • ParallaxativeAnimations using translate3d(0, x, 0) are jerky, but not as badly.
  • The Rellax library's animations, which use translate3d(0, x, 0), work perfectly smoothly.

You can see the comparison on this pen. (The jerkiness shows up best in Firefox.) My library is on Bitbucket.

I don't know where the problem in my library lies and I don't know how to figure it out. Here is an abridged paste of where the heavy lifting is done while scrolling in the ScrollAnimation class that works smoothly:

getCSSValue(set, scrollPosition) {     return set.valueFormat.replace(set.substitutionString, ((set.endValue - set.startValue) * scrollPosition + set.startValue).toString() + set.unit) }  updateCSS() {     var cssValues = [];      var scrollPosition = this.scrollDetector.clampedRelativeScrollPosition();      var length = this.valueSets.length;     for(var i = 0; i < length; i++) {         cssValues.push(getCSSValue(valueSets[i], scrollPosition) );     }      this.setCSS(cssValues);     this.ticking = false; }  requestUpdate() {     if(!this.ticking) {         requestAnimationFrame(() => { this.updateCSS(); });     }      this.ticking = true; } 

And here's the equivalent in the ParallaxativeAnimation class that is jerky:

updateCSS() {     var scrollPosition = this.scrollDetector.clampedRelativeScrollPosition();     var cssValues = [];      var length = this.valueSets.length;     for(var i = 0; i < length; i++) {         var scrollTranslate = -((this.scrollTargetSize - this.valueSets[i].parallaxSize) * scrollPosition);          cssValues.push(             this.valueSets[i].valueFormat.replace(this.valueSets[i].substitutionString, scrollTranslate.toString() + 'px')         );     }      this.setCSS(cssValues);     this.ticking = false; }  requestUpdate() {     if(!this.ticking) {         requestAnimationFrame(() => { this.updateCSS(); });     }      this.ticking = true; } 

The math doesn't seem any more complicated, so I can't figure how that's affecting animation performance. I thought the difference might have been my styling on the parallax image, but in the pen above, the Rellax version has the exact same CSS on it, but animates perfectly smoothly. Rellax seems to maybe be doing more complicated math on each frame:

var updatePosition = function(percentage, speed) {   var value = (speed * (100 * (1 - percentage)));   return self.options.round ? Math.round(value) : Math.round(value * 100) / 100; };   // var update = function() {   if (setPosition() && pause === false) {     animate();   }    // loop again   loop(update); };  // Transform3d on parallax element var animate = function() {   for (var i = 0; i < self.elems.length; i++){     var percentage = ((posY - blocks[i].top + screenY) / (blocks[i].height + screenY));      // Subtracting initialize value, so element stays in same spot as HTML     var position = updatePosition(percentage, blocks[i].speed) - blocks[i].base;      var zindex = blocks[i].zindex;      // Move that element     // (Set the new translation and append initial inline transforms.)     var translate = 'translate3d(0,' + position + 'px,' + zindex + 'px) ' + blocks[i].transform;     self.elems[i].style[transformProp] = translate;   }   self.options.callback(position); }; 

The only thing I can really tell from Chrome Developer Tools is that the framerate isn't dipping too far below 60 fps, so maybe it's not that I'm doing too much work each frame, but that I'm doing something mathematically incorrect when I calculate the position?

So I don't know. I'm clearly in way over my head here. I'm sorry to throw a whole library at StackOverflow and say "FIX IT", but if anyone can tell what I'm doing wrong, or tell me how to use Developer Tools to maybe figure out what I'm doing wrong, I'd appreciate it very much.


EDIT

Okay, I've figured out that the most important factor in the jitteriness of the scrolling is the height of the element being translated. I had a miscalculation in my library that was causing the background images to be much taller than they needed to be when my scrollPixelsPerParallaxPixel property was high. I'm in the process of trying to correct that now.

2 Answers

Answers 1

Aside from the calculations, you could try running it asynchroneously by using Promise:

await Promise.all([   loop(update); ]); 

just to see if it has a positive impact on the performance.

I'd comment, but I don't have enough reputation yet.

Answers 2

Anything touching the DOM will be slow. CSS animations are fine, but if you update the CSS you are touching the DOM and it will be slow. Consider using a canvas element instead!

Read More

Monday, October 9, 2017

Change CSS of inner div when scroll reaches that div

Leave a Comment

I am attempting to implement a scroll function where the CSS of the inner div's change when it reaches a certain height from the top.

var $container = $(".inner-div"); var containerTop = $container.offset().top; var documentTop = $(document).scrollTop(); var wHeight = $(window).height(); var minMaskHeight = 0; var descriptionMax = 200; var logoMin = -200; var maskDelta = descriptionMax - minMaskHeight; var $jobOverview = $container.find(".right"); var $jobLogo = $container.find(".left");  var curPlacementPer = ((containerTop - documentTop) / wHeight) * 100; var topMax = 85; var center = 20; var bottomMax = -15;  //console.log("Placement: " + curPlacementPer);  function applyChanges(perOpen) {   var maskHeightChange = maskDelta * (perOpen / 100);   var opacityPer = perOpen / 100;   var newDescriptionLeft = descriptionMax - maskHeightChange;   var newLogoLeft = logoMin + maskHeightChange;   if (newDescriptionLeft <= 0) newDescriptionLeft = 0;   if (newLogoLeft >= 0) newLogoLeft = 0;   if (opacityPer >= 1) opacityPer = 1;   $jobOverview.css({     transform: "translate(" + newDescriptionLeft + "%,-50%)",     opacity: opacityPer   });   $jobLogo.css({     transform: "translate(" + newLogoLeft + "%,-50%)",     opacity: opacityPer   }); }  if (window.innerWidth > 640) {   $container.removeClass("mobile");   // console.log("Placement: " + curPlacementPer);    if (curPlacementPer <= topMax /*&& curPlacementPer >= center*/ ) {     var perOpen = ((topMax - curPlacementPer) / 25) * 100;     applyChanges(perOpen);   } else if (curPlacementPer < center /*&& curPlacementPer >= bottomMax*/ ) {     var perOpen = (((bottomMax - curPlacementPer) * -1) / 25) * 100;     applyChanges(perOpen);   } else {     $jobOverview.css({       transform: "translate(200%,-50%)",       opacity: "0"     });     $jobLogo.css({       transform: "translate(-300%,-50%)",       opacity: "0"     });   } 
<div class="outer-div">   <div class="inner-div first">     <div class="left"></div>     <div class="right"></div>   </div>   <div class="inner-div second">     <div class="left"></div>     <div class="right"></div>   </div>   <div class="inner-div third">     <div class="left"></div>     <div class="right"></div>   </div>   <div class="inner-div fourth">     <div class="left"></div>     <div class="right"></div>   </div> </div> 

Currently, all of the inner div's gets changed at the same time.
I noticed that when I change the $container class to equal '.first' and specify it more it works.

Is there any way to make the inner div's change separately relative to its height from the top? Any way I can iterate the scroll function so I can add more inner div's in the future and not have to worry about changing my scroll function?

4 Answers

Answers 1

consider using 3rd party jQuery plugin for easier job, like one of these:

https://github.com/xobotyi/jquery.viewport

or

https://github.com/zeusdeux/isInViewport

then you can have additional element selector e.g.: ":in-viewport"

so you can:

$(window).on('scroll',function() {     $('div').not(':in-viewport').html('');     $('div:in-viewport').html('hello'); }); 

Answers 2

In raw JavaScript, this is my answer:

// Define the element -- The '#fooBar' can be changed to anything else. var element = document.querySelector("#fooBar");  // Define how much of the element is shown before something happens. var scrollClipHeight = 0 /* Whatever number value you want... */;  // Function to change an element's CSS when it is scrolled in. const doSomething = function doSomething() {      /** When the window vertical scroll position plus the      *   window's inner height has reached the      *   top position of your element.     */     if (            (window.innerHeight + window.scrollY) - (scrollClipHeight || 0) >=             element.getBoundingClientRect().top     )         // Generally, something is meant to happen here.         element.style = "/* Yay, some CSS! */" };  // Call the function without an event occurring. doSomething();  // Call the function when the 'window' scrolls. addEventListener("scroll", doSomething, false) 

This is the method I use. If there are other methods, I'd love to see them as well but this is my answer for now.

Answers 3

Below is the sample snippet code, Hope it'll work for you:

$(document).ready(function(){  	topMax = 100;    topMin = 25;    $(document).scroll(function(){      $('.inner-div').each(function(){		      	if($(this).offset().top-$(window).scrollTop()<=topMax && $(this).offset().top-$(window).scrollTop()>=topMin){        	$(this).css({'background':'#c7c7c7'});        }else{        	$(this).css({'background':'inherit'});        }    	});    });    });
div{    width:100%;    border:1px solid red;    padding:5px;  }  div.inner-div{    border: 1px dashed green;    height: 100px;  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>  <div class="outer-div">    <div class="inner-div first">      <div class="left"></div>      <div class="right"></div>    </div>    <div class="inner-div second">      <div class="left"></div>      <div class="right"></div>    </div>    <div class="inner-div third">      <div class="left"></div>      <div class="right"></div>    </div>    <div class="inner-div fourth">      <div class="left"></div>      <div class="right"></div>    </div>  </div>

Happy to help you! :)

Answers 4

Check if current scroll offset from top is bigger than the element offset from the top:

$(window).scroll(function() {     var height = $(window).scrollTop();     var element = $('#changethis'); //change this to your element you want to add the css to     if(height  > element.offset().top) {         element.addClass('black'); //add css class black (change according to own css)     } }); 

Html:

<div id="changethis">Test</div> 

Css:

body { height:2000px;  } .black {   background-color:black;   color:white;   padding:20px; } 

Demo: https://codepen.io/anon/pen/WZdEap

You could easily implement this in your existing code.

Read More

Wednesday, August 9, 2017

How to programmatically scroll window on iPad?

Leave a Comment

My application includes several features that programmatically scroll to particular elements on a page. Unfortunately, it's not working on Safari/iPad. I have tried the following methods of scrolling:

window.scroll(0, y);  window.scrollTo(0, y);  $(window).scrollTop(y);  $('html, body').animate({     scrollTop: y }); 

Is it simply not possible to programmatically scroll the window on Safari/iPad, or am I just doing it incorrectly? All of these methods worked for all browsers I tested on the PC.

4 Answers

Answers 1

Have you tried any libraries? http://iscrolljs.com/ looks promising, but I cannot test (no iOS device).

  • Granular control over the scroll position, even during momentum. You can always get and set the x,y coordinates of the scroller.
  • Out of the box multi-platform support. From older Android devices to the latest iPhone, from Chrome to Internet Explorer.

Answers 2

I haven't found a way to scroll the window programmatically on iPad. One possible workaround is to wrap the page content in a fixed div container, and to scroll it by changing the div's scrollTop property. You can see that method in this codepen. I tested it successfully on iPad with Safari and Chrome, and on Windows with Firefox, Chrome and IE11.

HTML

<div id="container">     <div class="div1"></div>     <div class="div2"></div>     <div class="div3"></div>     ... </div> 

CSS

div#container {     position: fixed;     left: 0;     top: 0;     width: 100%;     height: 100%;     overflow-y: auto; } div {     height: 100px; } .div1 {     background-color: red; } .div2 {     background-color: green; } .div3 {     background-color: yellow; } 

Javascript

var container = document.getElementById("container"); setInterval(function() {     container.scrollTop += 1; }, 20); 

Answers 3

Its working fine for me on safari and iPad:

$('html, body').animate({         scrollTop: 0  }, 1000); 

Not sure but you can try it by giving some scroll animation timings in milliseconds.

Answers 4

i am using following code of jquery and it work for every browser (i dont user IE :) )

  $("html,body").animate({     scrollTop: 0 }, "slow"); 

Cross-browser scroll to top:

    if($('body').scrollTop()>0){         $('body').scrollTop(0);         //Chrome,Safari     }else{         if($('html').scrollTop()>0){    //IE, FF             $('html').scrollTop(0);         }     }  

Cross-browser a div with id = test_id:

    if($('body').scrollTop()>$('#test_id').offset().top){         $('body').scrollTop($('#test_id').offset().top);         //Chrome,Safari     }else{         if($('html').scrollTop()>$('#test_id').offset().top){    //IE, FF             $('html').scrollTop($('#test_id').offset().top);         }     }  
Read More

Saturday, July 8, 2017

scrollBy doesn't work properly in nested recyclerview

Leave a Comment

I have a vertically scrolling RecyclerView with horizontally scrolling inner RecyclerViews just like this.

expl

With this implementation, users can scroll each horizontal recyclerview synchronously. However, when a user scroll vertically to the parent recyclerView, a new horizontal recyclerview which has just attached on window doesn't display on same scroll x position. This is normal. Because it has just created.

So, I had tried to scroll to the scrolled position before it was displayed. Just like this:

Note: this is in adapter of the parent recyclerview whose orientation is vertical.

 @Override     public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {         super.onViewAttachedToWindow(holder);         CellColumnViewHolder viewHolder = (CellColumnViewHolder) holder;         if (m_nXPosition != 0) {              // this doesn't work properly               viewHolder.m_jRecyclerView.scrollBy(m_nXPosition, 0);         }     } 

enter image description here

As you can see, scrollBy doesn't effect for row 10, row 11, row 12 and row 13 After that, I debugged the code to be able find out find out what's happening. When I set scroll position using scrollBy, childCount() return zero for row 10, row 11, row 12 and row 13 So they don't scroll. But why ? and Why others work ?

  • How can I fix this ?
  • Is onViewAttachedToWindow right place to scroll new attached recyclervViews ?

Note: I have also test scrollToPosition(), it doesn't get any problem like this. But I can't use it at my case. Because users can scroll to the any x position which may not the exact position. So I need to set scroll position using x value instead of the position.

Edit: You can check The source code

1 Answers

Answers 1

I found a solution that is use scrollToPositionWithOffset method instead using scrollBy. Even if both of two scroll another position, they have really different work process in back side.

For example: if you try to use scrollBy to scroll any pixel position and your recyclerView had not been set any adapter which means there is no any data to display and so it has no any items yet, then scrollBy doesn't work. RecyclerView uses its layoutManager's scrollBy method. So in my case, I am using LinearLayoutManager to the horizontal recyclerViews.

Lets see what it's doing :

int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {         if (getChildCount() == 0 || dy == 0) {             return 0;         }         mLayoutState.mRecycle = true;         ensureLayoutState();         final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;         final int absDy = Math.abs(dy);         updateLayoutState(layoutDirection, absDy, true, state);         final int consumed = mLayoutState.mScrollingOffset                 + fill(recycler, mLayoutState, state, false);         if (consumed < 0) {             if (DEBUG) {                 Log.d(TAG, "Don't have any more elements to scroll");             }             return 0;         }         final int scrolled = absDy > consumed ? layoutDirection * consumed : dy;         mOrientationHelper.offsetChildren(-scrolled);         if (DEBUG) {             Log.d(TAG, "scroll req: " + dy + " scrolled: " + scrolled);         }         mLayoutState.mLastScrollDelta = scrolled;         return scrolled;     } 

As you can see scrollBy ignores the scroll intentions if there is no any child at that time.

  if (getChildCount() == 0 || dy == 0) {      return 0;   } 

On the other hand scrollToPosition can work perfectly even if there is no any set data yet.

According to the Pro RecyclerView slide, the below sample works perfectly. However you can not do that with scrollBy.

void onCreate(SavedInstanceState state) {     ....     mRecyclerView.scrollToPosition(selectedPosition);     mRecyclerView.setAdapter(myAdapter); } 

As a result, I have changed little thing to use scrollToPositionWithOffset().

Before this implementation I was calculating the exact scroll x position as a pixel.

After that, when the scroll came idle state, calculating the first complete visible position to the first parameter of the scrollToPositionWithOffset().

For second parameter which is the offset, I am getting the value using view.getLeft() function which helps to get left position of this view relative to its parent.

enter image description here

And it works perfectly!!

Read More

Monday, May 29, 2017

Scrolling gets “stuck” when using nested scroll views

Leave a Comment

Problem description:

I have one iOS project for browsing images with nested UIScrollViews which is inspired by famous Apple's PhotoScroller. The problem is what sometimes scrolling just "stuck" when image is zoomed width- or height-wise. Here is an example of how it looks on iPhone 4s for image of size 935x1400 zoomed height-wise:

(I start dragging to left, but scroll view immediatly discard this action and image get "stuck")

Scroll problem

Workaround:

I found kind of workaround by adjusting content size of inner scroll view to nearest integer after zooming:

// Inside ImageScrollView.m  - (void)setZoomScale:(CGFloat)zoomScale {     [super setZoomScale:zoomScale];     [self fixContentSizeForScrollingIfNecessary]; }  - (void)zoomToRect:(CGRect)rect animated:(BOOL)animated {     [super zoomToRect:rect animated:animated];     [self fixContentSizeForScrollingIfNecessary]; }  - (void)fixContentSizeForScrollingIfNecessary {     if (SYSTEM_VERSION_LESS_THAN(@"10.2"))     {         CGSize content = self.contentSize;         content.width = rint(content.width);         content.height = rint(content.height);         self.contentSize = content;     } } 

But this fix not perfect - some images now are shown with one-pixel wide stripes on sides. For example, on iPhone 6 for image of size 690x14300 it shows this at the bottom:

iPhone 6

Also, oddly enough, I'm able to reproduce this problem on iOS 7.0 - 10.1, but everything works correctly on iOS 10.2 and greater.

Question:

So, what I am doing wrong? Can my fix be improved?

Test Project:

I created simple test project to illustrate described problem - NestedScrollingProblems. Please note what my version of ImageScrollView is slightly different from Apple's one because I applied another rules for zooming. Also, workaround is commented out by default. (project code is a bit messy, sorry about that)

1 Answers

Answers 1

Can't comment on posts (not enough reps yet).

But by the looks of it (Apple's Docs) this project deinits images on scroll, then re-inits them when they are going to be loaded (see line 350 in UIScrollView.m). And also I have noticed a comment inside of the ImageScrollView.m (line 346) that explicitly says that this class is designed to avoid caching. Which is a practical way for a demo, but not for production, or real-world application that have ui-loading speed in mind like what you want to.

I also noticed that your app has to scroll much further to engage the pagination.. which is either some error in the code, or it might be the lag itself that hangs the main thread from running the pagination fluidly. Or if you intended to have such a wide threshold for pagination.. i'd recomend reducing it for better user experience since modern smartphones has screens much wider than that of the iPhone 4S.

To address this,

I found this post (bellow) on SO that seems to have a pretty decent obj-c method for caching, and fetching image data from such a cache post app-launch. You should be able to work it into post-launch methods pretty simply as well, or even use it with networking to download images from the web. You'd just have to make sure that your UIImage views are properly linked to the url strings you use, either through a set of custom string variables for each image view, or by subclassing UImageView into a custom class, and adding the cache method into it to make your code look simpler. Here's the method and NSCahe class from that post from iOSfleer

NSCache Class:

@interface Sample : NSObject  + (Sample*)sharedInstance;  // set - (void)cacheImage:(UIImage*)image forKey:(NSString*)key; // get - (UIImage*)getCachedImageForKey:(NSString*)key;  @end  #import "Sample.h"  static Sample *sharedInstance;  @interface Sample () @property (nonatomic, strong) NSCache *imageCache; @end  @implementation Sample  + (Sample*)sharedInstance {     static dispatch_once_t onceToken;     dispatch_once(&onceToken, ^{         sharedInstance = [[Sample alloc] init];     });     return sharedInstance; } - (instancetype)init {     self = [super init];     if (self) {         self.imageCache = [[NSCache alloc] init];     }     return self; }  - (void)cacheImage:(UIImage*)image forKey:(NSString*)key {     [self.imageCache setObject:image forKey:key]; }  - (UIImage*)getCachedImageForKey:(NSString*)key {     return [self.imageCache objectForKey:key]; } 

And so as to not change too much of what you've made, it seems that by changing the displayImageWithInfo method inside of ImageScrollview.m to the following one (using the caching method), it seems to work better after initial load. I'd also go a step further if I were you, and implement a loop-style method in the controller's viewDidLoad method to cache those images right away for faster loading at launch. But that's up to you.

- (void)displayImageWithInfo:(ImageItem*)imageInfo {     CGSize imageSize = (CGSize){.width = imageInfo.width, .height = imageInfo.height};      // clear the previous imageView     [self.imageView removeFromSuperview];     self.imageView = nil;      // reset our zoomScale to 1.0 before doing any further calculations     self.zoomScale = 1.0;      self.imageView = [[UIImageView alloc] initWithFrame:(CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size = imageSize}];      UIImage *image = [[Sample sharedInstance] getCachedImageForKey:imageInfo.path];     if(image)     {         NSLog(@"This is cached");         ((UIImageView*)self.imageView).image = image;     }     else{          NSURL *imageURL = [NSURL URLWithString:imageInfo.path];         UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:imageURL]];          if(image)         {             NSLog(@"Caching ....");             [[Sample sharedInstance] cacheImage:image forKey:imageInfo.path];             ((UIImageView*)self.imageView).image = image;         }      }       [self addSubview:self.imageView];      [self configureForImageSize:imageSize]; } 

I would also recomend working around this without removing views from their superview on scroll.. the adding of views is a very heavy task. And coupled with image loading, can be horrendously heavy for a small cpu like the ones on smartphones (since they don't have GPU's.. yet). To emphasize this, Apple even mentions that it does not re-render UIImages once they are displayed, the wording is subtle here, but it clearly does not mention optimized removing then re-adding and rendering views after they have been displayed once (such as is it in this case). I think the intended use here is to display the ImageView, and simply change it's image element afterwards after the controller is displayed.

Although image objects support all platform-native image formats, it is recommended that you use PNG or JPEG files for most images in your app. Image objects are optimized for reading and displaying both formats, and those formats offer better performance than most other image formats.

This is why views are usually added/initialized on their super view before any of the visible loading methods like viewWillAppear and viewDidAppear, or if it is done post-initial load they are rarely de-initialized, their content is often the only thing altered and even then it is usually done asynchronously (if downloading from the web), or it is done from a cache which can also be done automatically with some initializers (you can add this to what I am recommending):

Use the imageNamed:inBundle:compatibleWithTraitCollection: method (or the imageNamed: method) to create an image from an image asset or image file located in your app’s main bundle (or some other known bundle). Because these methods cache the image data automatically, they are especially recommended for images that you use frequently.

On a personnal note, I would try to take the approach of UICollectionViews. Notably, they have delegates which handle the caching of content automatically when views scroll out of the window (which is exactly what this demo is). You can add custom code to those methods too to better control the scrolling effect on those views as well. They might be a bit tricky to understand at first, but I can attest that what you are trying to accomplish here can be replicated with a fraction of the code this demo uses. I'd also take the fact that this demo was built in 2012 as a hint.. it is a very old demo and UICollectionViews appeared at the time this demo was last updated. So i'd say that this is what Apple is has been aiming for ever since because all content-oriented UIView subclasses have some kind of inheritance from UIScrollView anyways (UICollectionView, UITableView, UITextView, etc.). Worth a look! UICollectionViews.

Read More

Tuesday, April 25, 2017

Scroll with iframe in phonegap iOS

Leave a Comment

If have an iframe in my PhoneGap app. The frame has been given a height of 1000. By adjusting its width to 50% I can scroll by touching the parent on the space next to the frame. But when I try to scroll by touching the frame itself, there is no response.

I looked for this problem and some issues have been reported that came with a solution including the -webkit-overflow-scrolling: touch; but no luck.

#content_wrap {     display: inline-block;     float:left;     width:100%;     overflow-x:hidden;     position:relative;     height:auto;     z-index:300; }   #content_wrap  .content_container {     position:absolute;     left:0px;     display:inline-block;     float:left;     width:100%;     padding:0;     min-height:100%;     height:auto;     background-color:#FFF; }  #tickets {     display:inline-block;     float:left;     width:50%;     margin:0px;     height:auto; }  #ticketFrame {     height:1000px;     display:inline-block;     float:left;     width:100%; } 

The html:

<div id="content_wrap">    <div class="content_container">       <div id="tickets">          <iframe src="someurl" frameborder="0" id="ticketFrame"></iframe>       </div>    </div> </div> 

I am a fan of using display inline block and float left as u can see ;)

What to do to be able to scroll with touchscreen in phonegap?

1 Answers

Answers 1

maybe problem is your iframe tag? </iframe">

if its not, add/change your css and try again.

html, body {     height: 100%;     min-height: 100%;     margin: 0;     padding: 0; }  #content_wrap {     display: inline-block;     float:left;     width:100%;     overflow-x:hidden;     position:relative;     height:100%;     z-index:300; }  #content_wrap  .content_container {     position:absolute;     left:0px;     display:inline-block;     float:left;     width:100%;     padding:0;     min-height:100%;     height:auto;     background-color:#FFF; }  #tickets {     display:inline-block;     float:left;     width:50%;     margin:0px;     height:100%;     right: 0;      bottom: 0;      left: 0;     top: 0;     -webkit-overflow-scrolling: touch;     overflow-y: scroll; }  #ticketFrame {     height:1000px;     display:inline-block;     float:left;     width:100%; } 
Read More

Friday, January 20, 2017

horizontally scroll table in Angular md-content

Leave a Comment

In Angular 1.5 I have a table in an <md-content>. I dynamically add columns to the table, and at a certain point horizontal scrollbars appear. This is good.

But the bad part is that the new columns are not visible. How could I programmatically scroll my <md-content> horizontally so that new columns are visible?

2 Answers

Answers 1

Have you looked into scrollLeft? You can get the position of the scrolled element, and then scroll the parent to that position:

container.scrollLeft = childToScrollTo.getBoundingClientRect().left; 

You could certainly build this into a directive if you needed to, or you can just run something like this after you add a column. Here's a quick demo:

var scroll = function(){    var container = document.getElementById('container');    var childToScrollTo = document.getElementById('scrollto');        container.scrollLeft = childToScrollTo.getBoundingClientRect().left;  }
#container{    white-space: nowrap;    overflow: auto;    width: 400px;  }    .child{    display:inline-block;  }
<button onclick="scroll()">scroll</button>  <div id="container">    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child" id="scrollto">scroll here!</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>    <div class="child">child</div>  </div>

Answers 2

As I post in a comment, here you have a working plunker using angular-scroll-glue directive.

The key here is attaching scroll-glue-right directive to your md-content.

<md-content scroll-glue-right>   ... </md-content> 

See complete code here

EDIT: If you want to scroll programatically instead of automatically like in the first plunker, you can bind scroll-glue-right to a controller attribute. Example:

<md-content scroll-glue-right="glued"> ... </md-content> 

When glued is set to true, scroll will be fired. Working plunker here

Hope it helps

Read More

Wednesday, April 20, 2016

Launch an animation onstart CustomViewPager

Leave a Comment

I succeed to create an animation at the start of my CustomViewPager which act like a Carousel. So here, my items came from the left and goes to the right in 3 seconds. The thing is it's just a translation I was wondering if it's possible to just make my viewpager scroll from far away to his final position.

Do you see a way to do this ? Regards.

Edit : So I try something else and I have created my custom ScrollToAnimation. I succeed to create what I want but the movement is not smooth can you help me. My new code :

import android.support.v4.view.ViewPager; import android.view.animation.Animation; import android.view.animation.Transformation;  import java.util.Calendar;  public class ScrollToAnimation extends Animation {     private int currentIndex = 0, nbChilds = -1, deltaT = 0;     private float fromX, toX;     private long animationStart;     private ViewPager viewpager;      public ScrollToAnimation(ViewPager viewpager, float fromX, float toX, int duration) {         this.viewpager = viewpager;         this.fromX = fromX;         this.toX = toX;          nbChilds = viewpager.getChildCount();         deltaT = duration / nbChilds;          setDuration(duration);         animationStart = Calendar.getInstance().getTimeInMillis();     }      @Override     protected void applyTransformation(float interpolatedTime, Transformation t) {         super.applyTransformation(interpolatedTime, t);         int offset = (int) (-fromX * interpolatedTime + fromX);         viewpager.scrollTo(offset, 0);          long animationProgression = Calendar.getInstance().getTimeInMillis() - animationStart;         currentIndex = (int) (animationProgression/deltaT);         if(viewpager.getCurrentItem() != currentIndex) {             viewpager.setCurrentItem(nbChilds-currentIndex, false);         }     } } 

The ViewPager :

import android.content.Context; import android.graphics.Canvas; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.animation.Animation; import android.view.animation.Interpolator;  import java.lang.reflect.Field; import java.lang.reflect.Method;  public class CarouselViewPager extends ViewPager {     private DisplayMetrics metrics;     private Animation animation;     private SpeedScroller mScroller = null;     private boolean animationNotStarted = true, leftToRight;      public CarouselViewPager(Context context) {         super(context);         postInitViewPager();         metrics = getContext().getResources().getDisplayMetrics();     }      public CarouselViewPager(Context context, AttributeSet attrs) {         super(context, attrs);         postInitViewPager();         metrics = getContext().getResources().getDisplayMetrics();     }      private void postInitViewPager() {         try {             Class<?> viewpager = ViewPager.class;             Field scroller = viewpager.getDeclaredField("mScroller");             scroller.setAccessible(true);             Field interpolator = viewpager.getDeclaredField("sInterpolator");             interpolator.setAccessible(true);              mScroller = new SpeedScroller(getContext(), (Interpolator) interpolator.get(null));             scroller.set(this, mScroller);         } catch (Exception e) {             Log.e("postInitViewPager", e.getMessage());         }     }      public void setScrollDurationFactor(double scrollFactor) {         mScroller.setScrollDurationFactor(scrollFactor);     }      @Override     public void setCurrentItem(int item, boolean smoothScroll) {         try {             Method method = ViewPager.class.getDeclaredMethod("setCurrentItemInternal", int.class, boolean.class, boolean.class, int.class);             method.setAccessible(true);             method.invoke(this, item, true, false, 1500);         } catch (Exception e) {             e.printStackTrace();             super.setCurrentItem(item, smoothScroll);         }     }      public void startAnimation(boolean leftToRight) {         animation = new ScrollToAnimation(this, ((metrics.widthPixels/2)+200)*2, 0, 2000);         animationNotStarted = false;         this.leftToRight = leftToRight;     }      private Canvas enterAnimation(final Canvas c) {         animationNotStarted = true;         startAnimation(animation);         scrollTo(0, 0);         return c;     }      @Override     protected void onDraw(Canvas canvas) {         if (!animationNotStarted) {             canvas = enterAnimation(canvas);         }         super.onDraw(canvas);     } } 

Edit2 :

Here a screenshot to help you to understand what I want. Actually I have a custom viewpager like this :

enter image description here

The animation I want is the follow :

  • When I launch the animation the item are far away.
  • After, they come from the left to te right (or the opposite) and stop to the selected item, but I want to have the scale effect when the items are scrolling.
  • I succeed to create the scaling effect thanks to an custom adapter

My issue, here is when I set the current item it's not smooth, do you have any idea ? Here is the code adapter

import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView;  import java.util.ArrayList;  public class CarouselAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener {     private float scale;     private MainActivity context;      private FragmentManager fragmentManager;     private ArrayList<Entity> entities = new ArrayList<>();     private ScaledFrameLayout cur = null, next = null;      public CarouselAdapter(MainActivity context, FragmentManager fragmentManager, ArrayList<Entity> mData) {         super(fragmentManager);         this.fragmentManager = fragmentManager;         this.context = context;         this.entities = mData;     }      @Override     public Fragment getItem(int position) {         if (position == MainActivity.FIRST_PAGE) {             scale = MainActivity.BIG_SCALE;         } else {             scale = MainActivity.SMALL_SCALE;         }         Fragment fragment = CarouselFragment.newInstance(context, entities.get(position), position, scale);         return fragment;     }      @Override     public int getItemPosition(Object object) {         return super.getItemPosition(object);     }      @Override     public int getCount() {         return entities.size();     }      @Override     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {         if (positionOffset >= 0f && positionOffset <= 1f) {             cur = getRootView(position);             cur.setScaleBoth(MainActivity.BIG_SCALE - MainActivity.DIFF_SCALE * positionOffset);              if (position < entities.size()-1) {                 next = getRootView(position + 1);                 next.setScaleBoth(MainActivity.SMALL_SCALE + MainActivity.DIFF_SCALE * positionOffset);             }         }     }      @Override     public void onPageSelected(int position) { }      @Override     public void onPageScrollStateChanged(int state) {}      private ScaledFrameLayout getRootView(int position) {         return (ScaledFrameLayout) fragmentManager.findFragmentByTag(this.getFragmentTag(position)).getView().findViewById(R.id.rootItem);     }      private String getFragmentTag(int position) {         return "android:switcher:" + context.carousel.getId() + ":" + position;     } } 

A more simply way, would be to change the current position of the current item without refresh everything, is it possible ? I mean without making any transition because as you can see I already have the translation and when I set the current item it's result with a conflict with my scrollto with the offset.

2 Answers

Answers 1

I think you have to make one of imageSlider with sooth scroll and image change with animation.

Android Image Slider library available in github now see below step to use it.

  • step 1: Gradle in compile below lib.

    dependencies { compile "com.android.support:support-v4:+" compile 'com.squareup.picasso:picasso:2.3.2' compile 'com.nineoldandroids:library:2.4.0' compile 'com.daimajia.slider:library:1.1.5@aar' } 
  • Step 2: Add permissions (if necessary) to your AndroidManifest.xml

     <!-- if you want to load images from the internet -->  <uses-permission android:name="android.permission.INTERNET" />    <!-- if you want to load images from a file OR from the internet -->  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
  • Step 3:Add the Slider to your layout:

    <com.daimajia.slider.library.SliderLayout android:id="@+id/slider" android:layout_width="match_parent" android:layout_height="200dp" /> 

    Now Make code in your Activity Here SlideShow.class in manage Code.

     public class SlideShow extends Activity {      ImageView mIVmenu;      SliderLayout sliderLayout;      ListView menu_list;      ArrayList<String> imgList = new ArrayList<String>();      int position;      Button btnBack;      static int adapter_position = 0;      String animation_name;       @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.slideshow);          sliderLayout = (SliderLayout) findViewById(R.id.sliderlayout);          menu_list = (ListView) findViewById(R.id.menu_list);          btnBack = (Button) findViewById(R.id.btn_back_slideshow);          menu_list.setAdapter(adapter);          // get Data from Intent array list and set on array list          imgList = getIntent().getStringArrayListExtra("arrayList");          position = getIntent().getExtras().getInt("position");         animation_name = SliderLayout.Transformer.Default.toString();      }      // call method for set images in slideshow and configure slideshow..    addImagesToSlider();     btnBack.setOnClickListener(new View.OnClickListener() {     @Override     public void onClick(View v) {         Intent i = new Intent(SlideShow.this, MainActivity.class);         startActivity(i);         finish();     } });  }   private void addImagesToSlider() {     for (int i = 0; i < imgList.size(); i++) {     TextSliderView textSliderView = new TextSliderView(this);     textSliderView.description("").image(new File(imgList.get(i))).setScaleType(BaseSliderView.ScaleType.CenterInside).setOnSliderClickListener(new BaseSliderView.OnSliderClickListener() {         @Override         public void onSliderClick(BaseSliderView slider) {         }     });     sliderLayout.addSlider(textSliderView);    }  sliderLayout.setPresetTransformer(animation_name); sliderLayout.setCustomAnimation(new DescriptionAnimation()); sliderLayout.stopAutoCycle(); sliderLayout.setCurrentPosition(position); }  BaseAdapter adapter = new BaseAdapter() { @Override public int getCount() {     return SliderLayout.Transformer.values().length; }  @Override public Object getItem(int position) {     return null; }  @Override public long getItemId(int position) {     return 0; }  @Override public View getView(final int position, View convertView, ViewGroup parent) {      View view;     view = LayoutInflater.from(parent.getContext()).inflate(R.layout.slidemenu_item, parent, false);     TextView tv = (TextView) view.findViewById(R.id.txtslideTitle);     final String str = SliderLayout.Transformer.values()[position].toString();     tv.setText(str);      view.setOnClickListener(new View.OnClickListener() {         @Override         public void onClick(View v) {              sliderLayout.setPresetTransformer(str);             animation_name = str;             notifyDataSetChanged();             mDrawer.closeMenu();         }     });     if (str.equals(animation_name)) {         adapter_position = position;                         tv.setBackgroundColor(getResources().getColor(R.color.colorAccent));     } else {  tv.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));     }     return view; }     }; } 

And more information refer this

Answers 2

Try to use smooth view pager, you can configure it's speed. All you need is to set it to 0 position, then make it visible, and then move it to target position, he will scroll smoothly to the target, you may apply any animation as in common view pager if you want. Also you may setPagingEnable to false and user wiil not scroll it by touch

public class SmoothScrollViewPager extends ViewPager {     private boolean enabled = true;     public SmoothScrollViewPager(Context context, AttributeSet attrs) {         super( context, attrs );         setMyScroller();     }      private void setMyScroller() {         try {             Class<?> viewpager = ViewPager.class;             Field scroller = viewpager.getDeclaredField("mScroller");             scroller.setAccessible(true);             scroller.set(this, new MyScroller(getContext()));         } catch (Exception e) {             e.printStackTrace();         }     }      @Override     public boolean onTouchEvent(MotionEvent event) {         if (this.enabled) {             return super.onTouchEvent(event);         }          return false;     }      public class MyScroller extends Scroller {         public MyScroller(Context context) {             super(context, new DecelerateInterpolator());         }          @Override         public void startScroll(int startX, int startY, int dx, int dy, int duration) {             super.startScroll(startX, startY, dx, dy, 1000 /*1 secs*/);         }      }      public void setPagingEnabled(boolean enabled) {         this.enabled = enabled;     } } 
Read More

Wednesday, March 30, 2016

RxJS Polling for row updates on infinite scroll

Leave a Comment

I was watching Matthew Podwysocki event on https://www.youtube.com/watch?v=zlERo_JMGCw 29:38

Where he explains how they solved scroll on netflix. Where user scroll for more data as previous data gets cleaned up and more adds up (but scroll back shows previous data again).

I wanted to do similar, but I grabbed netflix demo code:

function getRowUpdates(row) {   var scrolls = Rx.Observable.fromEvent(document, 'scroll');   var rowVisibilities =      scrolls.throttle(50)       .map(function(scrollEvent) {         return row.isVisible(scrollEvent.offset);       })       .distinctUntilChanged();    var rowShows = rowrowVisibilities.filter(function(v) {     return v;   });   var rowHides = rowrowVisibilities.filter(function(v) {     return !v;   });    return rowShows     .flatMap(Rx.Observable.interval(10))     .flatMap(function() {       return row.getRowData().takeUntil(rowHides);     })     .toArray(); } 

But I'm bit confused on how to pass new data or page data according to the scroll here.. Can someone give little explanation on how I can do the following:

  • fetch first list (I can do that)
  • fetch more list as user scroll down (using paging next page)
  • remove previous fetched data from memory, and refetch on request (scroll up).

1 Answers

Answers 1

Here is how I would do it in general lines. If this seems to give you satisfaction, I'll edit and add more details.

  1. Add a DIV or any desired tag that will be the location for this dynamic list.
  2. Each page of the list will be contained in another DIV which can contains anything. A page (to simplify next steps) will be the height of the window.
  3. Load 3 pages that covers, in all, three times the window height.
  4. When scrolling down and page1 is not visible (so page2.top is at window.top), add another below : page4. Still scrolling down, if page2 is not visible, put page1.height in a variable, remove the page1 from DOM and adjust scroll position by removing page1.height. Also, load page5.
  5. So now, there is page2 to page5 in the page which page2 and page5 are not visible. If page3 is fully visible, than page4 is not, otherwise a part of page3 and page4 are visible.
  6. When scrolling up and page2 is starting to be visible, load page1, add page1.height to scroll position and remove page5.
Read More

Friday, March 25, 2016

Prevent scrolling on a smart phone for a specific screen size

Leave a Comment

I simply need to prevent scrolling on a mobile device using JS and/or JQuery when a certain event occurs. I have a figure, when the user opens the figure the scrolling will be disabled, once it is closed, the scrolling will be enabled again. Target devices are:

  • any IPhone from 4s up to the latest one (5 + 6 included)

Here are some of the things that I've tried but didn't work out:

Method1 :

                    document.addEventListener('touchstart', this.touchstart);                     document.addEventListener('touchmove', this.touchmove);                      function touchstart(e) {                         e.preventDefault()                     }                      function touchmove(e) {                         e.preventDefault()                     } 

Method 2:

// left: 37, up: 38, right: 39, down: 40, // spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36 var keys = {37: 1, 38: 1, 39: 1, 40: 1};  function preventDefault(e) {   e = e || window.event;   if (e.preventDefault)       e.preventDefault();   e.returnValue = false;   }  function preventDefaultForScrollKeys(e) {     if (keys[e.keyCode]) {         preventDefault(e);         return false;     } }  function disableScroll() {   if (window.addEventListener) // older FF       window.addEventListener('DOMMouseScroll', preventDefault, false);   window.onwheel = preventDefault; // modern standard   window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE   window.ontouchmove  = preventDefault; // mobile   document.onkeydown  = preventDefaultForScrollKeys; }  function enableScroll() {     if (window.removeEventListener)         window.removeEventListener('DOMMouseScroll', preventDefault, false);     window.onmousewheel = document.onmousewheel = null;      window.onwheel = null;      window.ontouchmove = null;       document.onkeydown = null;   } 

Any other suggestions?

4 Answers

Answers 1

I fixed this by adding position: fixed; to .no-scroll which is applied to html and body when the figure is diplayed.

Added to JS to disable scrolling on open figure:

$('html, body').toggleClass('no-scroll'); 

Added to JS to enable scrolling on close figure:

$('html, body').removeClass('no-scroll'); 

CSS:

.no-scroll {     position: fixed; } 

Hopefully this will help others with similar problem.

Answers 2

You can simply disable document scroll with css:

$('body').addClass('overflow'); // use to disable scroll //- $('body').removeClass('overflow'); // use to enable scroll 

And css: (or use jQuery .css())

<style>     .overflow {         overflow: hidden;     } </style> 

Answers 3

I using sth like that:

$.fn.isolatedScroll = ->     @on 'mousewheel DOMMouseScroll', (e) ->       delta = e.wheelDelta or e.originalEvent and e.originalEvent.wheelDelta or -e.detail       bottomOverflow = @scrollTop + $(@).outerHeight() - (@scrollHeight) >= 0       topOverflow = @scrollTop <= 0       if delta < 0 and bottomOverflow or delta > 0 and topOverflow then e.preventDefault() 

And I use it ie. $(@).find('ul').isolatedScroll()

Answers 4

Disable scrolling in all mobile devices

Kindly check out the answer just below the accepted answer.

Read More

Wednesday, March 9, 2016

WatchOS snap to next row on scroll in WKInterfaceTable

Leave a Comment

Apple's own Activity app has an interesting feature that I try to re-implement in my own watch app: Each page in the activity app is scrollable and basically has 2 vertical pages. The first page is the circle and the second page shows more information.

But these pages don't normally scroll up and down when using the digital crown - they snap. So you can't scroll in between pages. Apple seems to be using a WKInterfaceTable with two rows but I don't find any documentation how you can implement the snapping behavior.

How did they do it?

1 Answers

Answers 1

You can use WKInterfaceTable's - (void)scrollToRowAtIndex:(NSInteger)index to scroll to a specific row. To get feedback from the digital crown directly you'd have to use WKInterfacePicker, but that may or may not work in your case.

Read More