14

I'm developing an app and ran into an issue where SingleChildScrollView starts at the top:

enter image description here

How do I make it start at the bottom like this:

enter image description here

The scroll view is implemented in the topContent, which is the top half of the screen:

    final topContent = Stack(
      children: <Widget>[
        Container(
            padding: EdgeInsets.only(left: 10.0),
            height: MediaQuery.of(context).size.height * 0.5,
            decoration: new BoxDecoration(
              image: new DecorationImage(
                image: new AssetImage("assets/images/drones1.jpg"),
                fit: BoxFit.cover,
              ),
            )),
        Container(
          height: MediaQuery.of(context).size.height * 0.5,
          padding: EdgeInsets.all(40.0),
          width: MediaQuery.of(context).size.width,
          decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
          child: SingleChildScrollView(      //scroll view implemented here 
            child: Center(
              child: topContentText,
            ),
          ),
        ),
        Positioned(
          left: 8.0,
          top: 60.0,
          child: InkWell(
            onTap: () {
              Navigator.pop(context);
            },
            child: Icon(Icons.arrow_back, color: Colors.white),
          ),
        )
      ],
    );

UPDATE: I assigned a controller and followed this link's example to try and use SchedulerBinding.instance.addPostFrameCallback to call the jumpTo function for scroll controller but it gives me an exception with the result the same as before where it is not scrolled down:

import 'package:garuda_academy_app/Constants.dart';
import 'Lesson.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

class DetailPage extends StatefulWidget {
  final Lesson lesson;
  DetailPage({Key key, this.lesson}) : super(key: key);

  @override
  _DetailPageState createState() => _DetailPageState(lesson: lesson);
}
class _DetailPageState extends State<DetailPage> {
  final Lesson lesson;
  ScrollController _scrollController;
  _DetailPageState({this.lesson});

  @override                             // I use the SchedularBinding here
  void initState() {
    super.initState();
    SchedulerBinding.instance.addPostFrameCallback((_) =>
      _scrollController.jumpTo(_scrollController.position.maxScrollExtent));
  }

  @override
  Widget build(BuildContext context) {
    final levelIndicator = Container(
      child: Container(
        child: LinearProgressIndicator(
            backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
            value: lesson.indicatorValue,
            valueColor: AlwaysStoppedAnimation(Colors.green)),
      ),
    );

    final course = Container(
      padding: const EdgeInsets.all(7.0),
      decoration: new BoxDecoration(
          border: new Border.all(color: Colors.white),
          borderRadius: BorderRadius.circular(5.0)),
      child: new Text(
        lesson.course,
        style: TextStyle(color: Colors.white),
      ),
    );

    final topContentText = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        SizedBox(height: 120.0),
        Icon(
          Icons.flight,
          color: Colors.white,
          size: 40.0,
        ),
        Container(
          width: 90.0,
          child: new Divider(color: Colors.green),
        ),
        SizedBox(height: 10.0),
        Text(
          lesson.title,
          style: TextStyle(color: Colors.white, fontSize: 45.0),
        ),
        SizedBox(height: 30.0),
        Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Expanded(flex: 1, child: levelIndicator),
            Expanded(
                flex: 6,
                child: Padding(
                    padding: EdgeInsets.only(left: 10.0),
                    child: Text(
                      lesson.level,
                      style: TextStyle(color: Colors.white),
                    ))),
            Expanded(flex: 1, child: course)
          ],
        ),
      ],
    );

    final topContent = Stack(
      children: <Widget>[
        Container(
            padding: EdgeInsets.only(left: 10.0),
            height: MediaQuery.of(context).size.height * 0.5,
            decoration: new BoxDecoration(
              image: new DecorationImage(
                image: new AssetImage(lesson.imagePath),
                fit: BoxFit.cover,
              ),
            )),
        Container(
          height: MediaQuery.of(context).size.height * 0.5,
          padding: EdgeInsets.all(40.0),
          width: MediaQuery.of(context).size.width,
          decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
          child: SingleChildScrollView(
            controller: _scrollController,      // Where I pin the ScrollController
            child: Center(
              child: topContentText,
            ),
          ),
        ),
        Positioned(
          left: 8.0,
          top: 60.0,
          child: InkWell(
            onTap: () {
              Navigator.pop(context);
            },
            child: Icon(Icons.arrow_back, color: Colors.white),
          ),
        )
      ],
    );

    final bottomContentText = Text(
      lesson.content,
      style: TextStyle(fontSize: 18.0),
    );
    final downloadButton = Container(
        padding: EdgeInsets.symmetric(vertical: 16.0),
        width: MediaQuery.of(context).size.width,
        child: RaisedButton(
          onPressed: () => {},
          color: Color.fromRGBO(58, 66, 86, 1.0),
          child:
              Text(DETAIL_PAGE_DOWNLOAD, style: TextStyle(color: Colors.white)),
        ));
    final bottomContent = Container(
      width: MediaQuery.of(context).size.width,
      padding: EdgeInsets.all(40.0),
      child: Center(
        child: Column(
          children: <Widget>[bottomContentText, downloadButton],
        ),
      ),
    );

    return Scaffold(
      body: Column(                  
        children: <Widget>[topContent, bottomContent],
      ),
    );
  }  
}

Exception: I/flutter ( 1567): Another exception was thrown: NoSuchMethodError: The getter 'position' was called on null.

Rajdeep
  • 2,246
  • 6
  • 24
  • 51

3 Answers3

11

Just add reverse true inside SingleChildScrollView:

SingleChildScrollView( reverse: true, child: Column(), )

İsmail Y.
  • 3,579
  • 5
  • 21
  • 29
8

I solved it by further adding (from the update) this when I defined the ScrollController:

  ScrollController _scrollController = new ScrollController(
    initialScrollOffset: 0.0,
    keepScrollOffset: true,
  );
Rajdeep
  • 2,246
  • 6
  • 24
  • 51
0

That's how it worked for me , I had to add a bit of small delay before firing the jump call , without the small delay it didn't work

  void initState() {
    super.initState();
    SchedulerBinding.instance?.addPostFrameCallback((_) async {
      await Future.delayed(Duration(milliseconds: 500));   
      _scrollController.jumpTo(_scrollController.position.maxScrollExtent);
    });
  }
Mahendra
  • 8,448
  • 3
  • 33
  • 56
Jay Shenawy
  • 953
  • 1
  • 12
  • 22