Thinking & coding: Snappy detail related to TweenAnimationBuilder

Today it is Friday. And what a great programming sessions I had this week. I am very happy with what I have achieved.

And especially with the things that I have learned.

As every Friday, there are no fundamental things planned in the programming.

In addition to cleanup the code, which I do every week on Friday, I've also posted my TODOs for next week. I will probably also have time to write code here or there this weekend. But programming in the weekend is always seen by me as extra time. And that is not planned.

What did I do today?

What did I do today? I incorporated a few simple animations into the app. The animations are not for show, but rather functional. Although they are beautiful, I think, ....... And like every Friday the code is cleaned up and structured where necessary.

Because I work without an appBar, I needed another 'BackButton' in my eventDetailScreen to return to the EventScreen with the EventCard's in the EventList. For that I used a simple FloatingActionButton. Placed these in the Theme colors and given the correct size. I have given this a light Animation to draw attention to the fact that the 'BackButton' is there. I personally think this position of the button is a successful position, because with mobile devices with a larger screen, you can easily operate the button with your thumb. An ergonomic place. Sorry for the left-handers among us, I had to make a choice. But I'll do fine hahaha.

I also animated the 'InfoButton' in the eventCards. And this also to point out to the user that more information can be obtained via this icon.

Both Animations are TweenAnimationBuilders, so the simplest out there. I have used the 'Transfor.scale. Below in the code I have highlighted the most important lines of code.

Snappy Detail in TweenAnimationBuilder

What is worth mentioning, I think, in connection with the performance of the app, is how we declare the variable of the 'Tween' in the Widget. First I had written this line without 'static final'. But what appears from the documentation. If you declare it like this, every time the animation is triggered, a new object will be created, which also needs the necessary memory. 

If we declare this with the 'static final' the initially created object will always be reused and the memory as well.


I thought that was a very important detail in the context of performance. Important enough to write an article about this. Applying every little possible improvement will only benefit the app. This is on paper. Now I can continue with peace of mind. '


The code.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
class EventCard extends StatelessWidget {
  final String titleCard;
  final String subTitleCard;
  final String dateCard;
  final String discriptionCard;
  final String imageCard;

  EventCard(
      {this.titleCard,
      this.dateCard,
      this.subTitleCard,
      this.discriptionCard,
      this.imageCard});

  static final Tween<double> _scaleBetween = Tween<double>(begin: 0.1, end: 1);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        //the transparant card with border
        height: 190.0,
        width: 280.0,
        decoration: BoxDecoration(
          color: Colors.transparent,
          borderRadius: BorderRadius.circular(50.0),
          border: Border.all(
            color: colorPalletDark,
            width: 3.0,
          ),
        ),
        child: Padding(
          //aligning the left side in the card
          padding: const EdgeInsets.only(left: 12.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              SizedBox(height: 2.0),
              Text(
                titleCard,
                style: CardTitleTextStyle,
              ),
              SizedBox(
                height: 15.0,
              ),
              Row(
                children: [
                  Text(dateCard, style: CardTextStyle),
                  SizedBox(
                    width: 70.0,
                  ),
                  TweenAnimationBuilder(
                    tween: _scaleBetween,
                    duration: Duration(milliseconds: 800),
                    builder: (context, scale, child) {
                      return Transform.scale(scale: scale, child: child);
                    },
                    child: IconButton(
                        icon: Icon(Icons
                            .info_outline), //#TODO implement the correct Icon
                        color: colorPalletDarkButAndText,
                        iconSize: 35,
                        onPressed: () {
                          Navigator.of(context).push(
                            MaterialPageRoute(
                              builder: (context) => EventDetailScreen(
                                eventDetailScreenTitle: titleCard,
                                eventDetailScreenDate: dateCard,
                                eventDetailScreenText: discriptionCard,
                              ),
                            ),
                          );
                        }),
                  )
                ],
              ),
              SizedBox(
                height: 2.0,
              ),
              Expanded(
                //use expanded to solve overflow
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Container(
                        margin: EdgeInsets.only(top: 5.00),
                        height: 70.0,
                        width: 145.0,
                        child: Text(subTitleCard, style: CardTextStyle)),
                    SizedBox(
                      width: 7.0,
                      height: 80.0,
                    ),
                    Container(
                      height: 120.0,
                      width: 110.0,
                      decoration: BoxDecoration(
                        boxShadow: [
                          BoxShadow(
                            blurRadius: 5.0,
                            color: Colors.grey,
                            offset: Offset(-2.0, -2.0),
                          )
                        ],
                        image: DecorationImage(
                            //#TODO replace the testimage with the imageCard
                            image: AssetImage(testImage),
                            fit: BoxFit.none),
                        borderRadius: BorderRadius.only(
                            topLeft: Radius.circular(50.0),
                            bottomRight: Radius.circular(47.0)),
                        //border: Border.all(color: Colors.blueAccent, width: 2.0),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}



  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
class EventDetailScreen extends HookWidget {
  final String eventDetailScreenTitle;
  final String eventDetailScreenSubTitle;
  final String eventDetailScreenDate;
  final String eventDetailScreenText;
  final String eventDetailScreenImage;

  const EventDetailScreen(
      {this.eventDetailScreenTitle,
      this.eventDetailScreenSubTitle,
      this.eventDetailScreenDate,
      this.eventDetailScreenText,
      this.eventDetailScreenImage});

  static final Tween<double> _scaleBetween = Tween<double>(begin: 0.1, end: 1);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: TweenAnimationBuilder(
        tween: _scaleBetween,
        duration: Duration(milliseconds: 800),
        builder: (context, scale, child) {
          return Transform.scale(scale: scale, child: child);
        },
        child: FloatingActionButton(
          elevation: 5.0,
          backgroundColor: colorPalletDarkButAndText,
          onPressed: () {
            Navigator.pop(context);
          },
          child: Icon(Icons.arrow_back),
        ),
      ),
      body: Column(
        children: [
          Expanded(
            flex: 4,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                Container(
                  constraints: BoxConstraints(
                    maxWidth: MediaQuery.of(context).size.width * 0.95,
                  ),
                  decoration: BoxDecoration(
                    boxShadow: [
                      BoxShadow(
                        color: Colors.grey,
                        offset: Offset(-4, -4),
                        blurRadius: 8,
                      )
                    ],
                    //#TODO change testimage with eventDetailScreenImage
                    image: DecorationImage(
                        image: AssetImage(testImage), fit: BoxFit.cover),
                    borderRadius: BorderRadius.only(
                        topLeft: Radius.circular(200.0),
                        bottomRight: Radius.circular(200.0),
                        bottomLeft: Radius.circular(30.0)),
                  ),
                ),
              ],
            ),
          ),
          Expanded(
            flex: 6,
            child: Container(
              //color: Colors.red,
              width: MediaQuery.of(context).size.width * 0.95,
              child: Padding(
                padding: const EdgeInsets.fromLTRB(20.0, 10.0, 8.0, 8.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    SizedBox(
                      height: 5.0,
                    ),
                    Text(
                      eventDetailScreenTitle,
                      style: SubTitle1TextStyle,
                    ),
                    SizedBox(
                      height: 10.0,
                    ),
                    Text(
                      eventDetailScreenDate,
                      style: SubTitle2TextStyle,
                    ),
                    SizedBox(
                      height: 20.0,
                    ),
                    Text(
                      eventDetailScreenText,
                      style: BodyText1TextStyle,
                    ),
                  ],
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}


So, I hope you have been able to follow a bit. In my old brain twists.

If you read something that you have a different opinion of, I'd love to read it in the comment section.


The next session will be something completely different. I am going to look for a way to load my data into the backend in a simple and fast way. Because if you have to enter all data in Firestore via the console, that won't get you anywhere.


So colleagues, friends, like-minded people, I hope to see you next time.

Do, believe and be happy

Stefaan

Comments

Popular posts from this blog

Thinking & coding: Linking Firebase to my Flutter App. Watch out for a important detail.

Software developer yes, but where to begin?

Thinking & coding: the Custom Navigation icons