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

Sunday, October 3, 2021

Flutter - design application with scrollbar enabled body with fixed header and footer | Header, Footer And Scrollable Body | How to create a scroll view with fixed footer with Flutter

A Flutter Widget that is scrollable with a sticky header to the header and footer to the bottom of screen of the end of the scroll body. You may simiply test with the example to see whether it is fit for your case. itemBuilder to build child widgets of scroll body; itemCount is the nunber of child widgets in scroll body.

Flutter is a mobile App SDK by Google which helps in creating Flutter: Material Design Using Scaffold AppBar Body Bottom Navigation Floating Action & Persistent Footer
ListView is the most commonly used scrolling widget. It displays its children one after another in the scroll direction. In the cross axis, the children are required to fill the ListView.

The default constructor takes an explicit List of children. This constructor is appropriate for list views with a small number of children because constructing the List requires doing work for every child that could possibly be displayed in the list view instead of just those children that are actually visible.

The ListView.builder constructor takes an IndexedWidgetBuilder, which builds the children on demand. This constructor is appropriate for list views with a large (or infinite) number of children because the builder is called only for those children that are actually visible.
The ListView.separated constructor takes two IndexedWidgetBuilders: itemBuilder builds child items on demand, and separatorBuilder similarly builds separator children which appear in between the child items. This constructor is appropriate for list views with a fixed number of children.
ListView documentation
Full example as below:
import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: ApplicationAppBar(),
        body: MyHomePageImpl()
    );
  }
}

class MyHomePageImpl extends StatefulWidget {
  @override
  _MyHomePageImpl createState() => _MyHomePageImpl();
}

class _MyHomePageImpl extends State<MyHomePageImpl> {
  final Future<int> loadDataAsync = Future<int>.delayed(
    Duration(seconds: 1), () async => processDataAsync(),
  );

  static Future<int> processDataAsync() async {
    return 20;
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(height: 5),
        Container(
          width: double.infinity,
          padding: EdgeInsets.all(20),
          margin: EdgeInsets.fromLTRB(10, 10, 7, 10),
          child: Text("Fixed Header"),
          decoration: BoxDecoration(
              color: Colors.white,
              border: Border.all(
                color: Colors.red,
              ),
              borderRadius: BorderRadius.all(Radius.circular(10))
          ),
        ),
        Expanded(
          child: FutureBuilder(
            builder: (context, AsyncSnapshot snapshot) {
              if (snapshot.hasError) {
                return Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      Icon(
                        Icons.error_outline,
                        color: Colors.red,
                        size: 60,
                      ),
                      Padding(
                        padding: const EdgeInsets.only(top: 16),
                        child: Text('Error: ${snapshot.error}'),
                      )
                    ],
                  ),
                );
              }
              if (!snapshot.hasData) {
                return Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      SizedBox(height: 20),
                      SizedBox(
                        child: CircularProgressIndicator(),
                        width: 60,
                        height: 60,
                      ),
                      const Padding(
                        padding: EdgeInsets.only(top: 16),
                        child: Text('Awaiting result...'),
                      )
                    ],
                  ),
                );
              }
              return Column(
                children: [
                  Expanded(
                    child: Container(
                      padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
                      margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
                      decoration: BoxDecoration(
                          color: Colors.white,
                          border: Border.all(
                            color: Colors.red,
                          ),
                          borderRadius: BorderRadius.all(Radius.circular(10))
                      ),
                      child: ListView.builder(
                        physics: ScrollPhysics(),
                        shrinkWrap: true,
                        itemCount: snapshot.data,
                        itemBuilder: (BuildContext context, int index) {
                          return Padding(
                            padding: EdgeInsets.fromLTRB(10, 0, 10, 10),
                            child: Container(
                              padding: EdgeInsets.all(20),
                              decoration: BoxDecoration(
                                  color: Colors.white,
                                  border: Border.all(
                                    color: Colors.lightGreen,
                                  ),
                                  borderRadius: BorderRadius.all(Radius.circular(10))
                              ),
                              child: Center(
                                child: Text(
                                  'Child $index',
                                  style: TextStyle(color: Colors.black, fontSize: 22),
                                ),
                              ),
                            ),
                          );
                        },
                      ),
                    )
                  )
                ],
              );
            },
            future: loadDataAsync,
          ),
        ),
        Container(
          width: double.infinity,
          padding: EdgeInsets.all(20),
          margin: EdgeInsets.fromLTRB(10, 10, 10, 0),
          child: Text("Fixed Footer"),
          decoration: BoxDecoration(
              color: Colors.white,
              border: Border.all(
                color: Colors.red,
              ),
              borderRadius: BorderRadius.all(Radius.circular(10))
          ),
        ),
        SizedBox(height: 5),
      ],
    );
  }
}

class ApplicationAppBar extends AppBar {
  ApplicationAppBar() : super(
    title: Text("Fixed Header & Footer"),
    actions: [
      IconButton(icon: Icon(Icons.add), onPressed: () {}),
    ],
  );
}
Sample screenshot:


Thursday, December 22, 2016

jQuery Check if element is visible after scrolling

Html Part:

<script src="//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<table style="width:100%;padding-top:100px;">
    <tr>
        <td style="width:50%;vertical-align:top">
            <h3>Partial Visibility Check</h3>

            <div class="scroll" style="height:320px;overflow:auto;border:1px solid blue;position:relative">
                <div class="check d1" style="height:100px;border:1px solid red">DIV 1</div>
                <div class="check d2" style="height:100px;border:1px solid red">DIV 2</div>
                <div class="check d3" style="height:100px;border:1px solid red">DIV 3</div>
                <div class="check d4" style="height:100px;border:10px solid red;padding-top:20px">DIV 4</div>
                <div style='padding:20px;position:relative;border:2px solid green;'>
                    <div style='border:2px solid blue;padding:30px;'>
                        <div class="check d5" style="height:100px;border:1px solid red">DIV 5</div>
                    </div>
                </div>
                <div class="check d6" style="height:100px;border:1px solid red">DIV 6</div>
                <div class="check d7" style="height:100px;border:1px solid red">DIV 7</div>
                <div class="check d8" style="height:100px;border:1px solid red">DIV 8</div>
            </div>
            <div class="log" style='height:140px;overflow:hidden'></div>
        </td>
        <td style="width:50%;vertical-align:top">
            <h3>Fully Visibility Check</h3>

            <div class="scroll full" style="height:320px;overflow:auto;border:1px solid blue;position:relative">
                <div style="height:3px"></div>
                <div class="check d1" style="height:100px;border:1px solid red">DIV 1</div>
                <div class="check d2" style="height:100px;border:1px solid red">DIV 2</div>
                <div class="check d3" style="height:100px;border:1px solid red">DIV 3</div>
                <div class="check d4" style="height:100px;border:1px solid red">DIV 4</div>
                <div class="check d5" style="height:100px;border:1px solid red">DIV 5</div>
                <div class="check d6" style="height:100px;border:1px solid red">DIV 6</div>
                <div class="check d7" style="height:100px;border:1px solid red">DIV 7</div>
                <div style="height:3px"></div>
            </div>
            <div class="log" style='height:128px;overflow:hidden'></div>
        </td>
    </tr>
</table>

jQuery Part:

var log = {};
$("div.scroll").scroll(function () {
    var boundary = $(this), block = boundary.closest("td"), full_view = boundary.hasClass("full");
    log = block.find(".log");
    boundary.find(".check").not(".visited").each(function () {
        var elem = $(this);
        var visited = isScrolledIntoView(boundary, elem, full_view);
        if (visited) {
            log.prepend("DIV.CLASS=\"" + elem.attr("class") + "\" VISITED<br/>");
        }
        else {
            log.prepend("DIV.CLASS=\"" + elem.attr("class") + "\" NOT VISITED<br/>");
        }
    });
});

function isScrolledIntoView(c, e, full_view) {
    var op = e[0].getBoundingClientRect().top - c[0].getBoundingClientRect().top;
    var oh = op + e[0].getBoundingClientRect().height;
    var v1 = c.height() > op && op >= 0;
    var v2 = oh <= c.height() && oh >= 0;
    return full_view === true ? (v1 && v2) : (v1 || v2);
}

Screenshot:




jQuery detect when user stops scrolling

<div class="scroll" style="height:300px;overflow:auto;border:1px solid blue">
    <div style="height:1000px"></div>
</div>
<div class="log"></div>

<script type="text/javascript">
    $("div.scroll").scroll(function() {
        clearTimeout($.data(this, 'scrollTimer'));
        $.data(this, 'scrollTimer', setTimeout(function() {
            $("div.log").prepend("Haven't scrolled in 250ms!<br/>");
        }, 250));
    });
</script>


Wednesday, November 16, 2016

Angular-js infinity scroll to load more data on window or other element scrolling


<!DOCTYPE html>
<html>
    <head>
        <title>Infinite scrolling to load more data using angular-js</title>
        <style type="text/css">
            div.scroll-test {
                height: 100%;
                background: #123213;
                color: #fff;
                overflow: auto;
                margin: 0 auto;
                padding: 0.5em;
            }
        </style>
        
        <script src="http://code.angularjs.org/1.2.12/angular.js"></script>
        <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
        
        <script type="text/javascript">
            var app = angular.module("myApp", []);
           
            app.controller("ScrollController", function($scope, $http) {
                $scope.items = ["You have to scroll down to load more items..."];
                $scope.loading = false;
                $scope.counter = 0;
                $scope.rows = 1;
                
                var s = "----------------------------------------------------";
                s += "-------------------------------------------------------";
                s += "-------------------------------------------------------";
                
                $scope.loadMore = function() {
                    if(!$scope.loading) {
                        $scope.loading = true;
                        $http({
                            method: "GET",
                            url: "http://localhost/scroll/data.html?counter=" + ($scope.counter++)
                        }).success(function(data, status, header, config) {
                            $scope.loading = false;
                            data = data.split("\n");
                            for(i = 0; i < data.length - 1; i++) {
                                $scope.items.push(($scope.rows++) + "=" + data[i]);
                            }
                            $scope.items.push(($scope.rows++) + s);
                        });
                    }
                };
                
                var params = {};
                window.location.search.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(str, key, value) {
                    params[key] = decodeURIComponent(value.replace(/\+/g, ' '));
                });
                var type = params.type === undefined ? '' : params.type;
                
                $scope.window = true;
                if(type == 'window') {
                    //Initializing the list
                    $scope.loadMore();
                }
                else if(type == 'div') {
                    $scope.window = false;
                    $("div.scroll-test").height(window.innerHeight - 130);
                    //Initializing the list
                    $scope.loadMore();
                }
                else {
                    $scope.items.push("You have to define 'type' parameter in url & value would be 'window' or 'div' as ?type=window");
                }
            });
            
            app.directive("windowScroll", function ($window) {
                return function(scope, element, attrs) {
                    angular.element($window).bind("scroll", function() {
                        if(scope.window && $window.pageYOffset + $(window).height() + 50 >= $(document).height()) {
                            scope.$apply(attrs.windowScroll);
                        }
                    });
                };
            });
           
            app.directive("divScroll", function() {
                return {    
                    restrict: 'A',
                    link: function(scope, element, attrs) {
                        var raw = element[0];
                        element.bind("scroll", function() {
                            if(!scope.window && raw.scrollTop + raw.offsetHeight + 50 >= raw.scrollHeight) {
                                scope.$apply(attrs.divScroll);
                            }
                        });
                    }
                }
            });
        </script>
    </head>

    <body>
         <div data-ng-app="myApp" data-window-scroll="loadMore()" data-ng-controller="ScrollController">
             <div>
                 <div class="scroll-test" data-div-scroll="loadMore()">
                     <p data-ng-repeat="item in items">
                         {{item}}
                     </p>
                 </div>
                <h1><i>INFINITE SCROLLING IN ANGULAR-JS<span data-ng-show="loading"> (Loading items...)</span></i></h1>              
             </div>       
         </div>
    </body>
</html>