Build Android Application using Flutter and WordPress API Part 3

This is part 3 of my tutorial series Build Android Application using Flutter and WordPress API. If you didn’t read previous parts please check them before you continue reading further.

Build Android Application using Flutter and WordPress API

Part 1 – we successfully connected our android application with WordPress API, we fetched list of posts and displayed them in nice looking Card Widgets. Part 2 – we fixed some issues with image loading and added cool fadein animation effect for featured images in our Card Widget. Most apps contain several screens for displaying different types of information. In our case we already have one screen VirtuoozaHome which is displaying list of posts. Now when our users can see list of posts and read short excerpt we want to give them ability to read full post content. Part 3 – add new screen to our application which will show full post content. We also need to add READ MORE Button to each of our Post Cards so users can navigate to screen with full post content.

PART 3

Add new screen

In Android terms, our screens would be new Activities. In iOS terms, new ViewControllers. In Flutter, screens are just Widgets!

We will add new dart file in our Flutter projects lib directory and name it virtuoozapost.dart (You can name it whatever you want :)). In this file we will define VirtuoozaPost Widget which extends StatelessWidget. That is our new screen. I already said in Flutter screens or pages are just Widgets. On this screen we will show full content of our post. We will also initiate new variable post which will hold post object and define class constructor.

Since we already have our posts fetched in our VirtuoozaHome screen I want to avoid calling WordPress API again because we already fetched all the data we want to show to our user. We already have posts featured image, title and full content. So we can just pass post object from our home screen VirtuoozaHome to our post details VirtuoozaPost screen when user clicks on READ MORE Button. This will be much faster and we avoid making additional HTTP requests to our WordPress API.

virtuoozapost.dart
import 'package:flutter/material.dart';

class VirtuoozaPost extends StatelessWidget {

  var post;
  VirtuoozaPost({Key key, @required var this.post}) : super(key: key);

  @override
  Widget build(BuildContext context) {}

}

In class constructor we will add post argument as required. And whenever we navigate to VirtuoozaPost screen it will require us to pass post object as argument.

Last thing we have to do is to add widgets in build method of our VirtuoozaPost screen to show post data in. I’ll keep it simple and add just Scaffold Widget with AppBar and Body. In AppBar I’ll show posts title as title and in Body I’ll add ListView which will contain posts featured image and full content inside Text Widget. I used TransparentImage package to add fadein animation to featured image like I showed you guys in Part 2.

WordPress API returns html tags in it’s response content so we had to filter them out and replace them with blank string to remove them.

new Text(post['content']['rendered'].replaceAll(new RegExp(r'<[^>]*>'), ''))

This is all we have to do in this file. Our VirtuoozaPost screen is now defined and ready to show us post content. You can check full code bellow.

virtuoozapost.dart
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';

class VirtuoozaPost extends StatelessWidget {

  var post;
  VirtuoozaPost({Key key, @required var this.post}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(post['title']['rendered']),
      ),
      body: new Padding(
        padding: EdgeInsets.all(16.0),
        child: new ListView(
          children: <Widget>[
            new FadeInImage.memoryNetwork(
              placeholder: kTransparentImage,
              image: post["featured_media"] == 0
                  ? ''
                  : post["_embedded"]["wp:featuredmedia"][0]["source_url"],
            ),
            new Text(post['content']['rendered'].replaceAll(new RegExp(r'<[^>]*>'), ''))
          ],
        ),
      ),
    );
  }
}

Add READ MORE button

preview
Preview in android emulator

Last thing we have to do is to add READ MORE Button Widget in our post cards on VirtuoozaPost screen. Open your main.dart file and in the the build method of our VirtuoozaHome Widget add: ButtonTheme bar with FlatButton Widget after Padding Widget in our Card Widget. FlatButton will be in the bottom right angle of our Card Widget like you can see in preview animation. We also need to define callback function for onPressed event. When user clicks Button we use Navigator to navigate to new VirtuoozaPost screen in our view. The push method will add a Route to the stack of routes managed by the Navigator. The push method requires a Route, but where does the Route come from? We can create our own, or use the MaterialPageRoute out of the box. The MaterialPageRoute is handy because it transitions to the new screen using a platform-specific animation. We will also pass current post object to VirtuoozaPost screen so we can show it’s full content.

main.dart
new ButtonTheme.bar(
  child: new ButtonBar(
    children: <Widget>[
      new FlatButton(
        child: const Text('READ MORE'),
          onPressed: () { Navigator.push(
            context, new MaterialPageRoute(
            builder: (context) => new VirtuoozaPost(post: posts[index]),
          ),
        ); 
       },
      ),
     ],
    ),
   ),

That’s all guys, you can test your application on your phone or emulator. Please check full application code bellow:

main.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:transparent_image/transparent_image.dart';
import 'virtuoozapost.dart';

void main() {
  runApp(MaterialApp(
      home: VirtuoozaHome()
  ));
}

class VirtuoozaHome extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => VirtuoozaHomeState();
}

class VirtuoozaHomeState extends State {

  // Base URL for our wordpress API
  final String apiUrl = "https://virtuooza.com/wp-json/wp/v2/";
  // Empty list for our posts
  List posts;

  // Function to fetch list of posts
  Future<String> getPosts() async {

    var res = await http.get(Uri.encodeFull(apiUrl + "posts?_embed"), headers: {"Accept": "application/json"});

    // fill our posts list with results and update state
    setState(() {
      var resBody = json.decode(res.body);
      posts = resBody;
    });

    return "Success!";
  }

  @override
  void initState() {
    super.initState();
    this.getPosts();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text("Virtuooza"),
          backgroundColor: Colors.blueAccent
      ),
      body: ListView.builder(
        itemCount: posts == null ? 0 : posts.length,
        itemBuilder: (BuildContext context, int index) {
          return Column(
            children: <Widget>[
              Card(
                child: Column(
                  children: <Widget>[
                    new FadeInImage.memoryNetwork(
                      placeholder: kTransparentImage,
                      image: posts[index]["featured_media"] == 0
                          ? 'images/placeholder.png'
                          : posts[index]["_embedded"]["wp:featuredmedia"][0]["source_url"],
                    ),
                    new Padding(
                      padding: EdgeInsets.all(10.0),
                      child: new ListTile(
                        title: new Padding(
                            padding: EdgeInsets.symmetric(vertical: 10.0),
                            child: new Text(posts[index]["title"]["rendered"])),
                        subtitle: new Text(
                            posts[index]["excerpt"]["rendered"].replaceAll(new RegExp(r'<[^>]*>'), '')
                        ),
                      )
                    ),
                      new ButtonTheme.bar(
                        child: new ButtonBar(
                            children: <Widget>[
                              new FlatButton(
                              child: const Text('READ MORE'),
                              onPressed: () { Navigator.push(
                                  context, new MaterialPageRoute(
                                  builder: (context) => new VirtuoozaPost(post: posts[index]),
                                  ),
                                ); },
                              ),
                            ],
                        ),
                      ),
                  ],
                ),
              )
            ],
          );
        },
      ),
    );
  }
}
virtuoozapost.dart
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';

class VirtuoozaPost extends StatelessWidget {

  var post;
  VirtuoozaPost({Key key, @required var this.post}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(post['title']['rendered']),
      ),
      body: new Padding(
        padding: EdgeInsets.all(16.0),
        child: new ListView(
          children: <Widget>[
            new FadeInImage.memoryNetwork(
              placeholder: kTransparentImage,
              image: post["featured_media"] == 0
                  ? 'images/placeholder.png'
                  : post["_embedded"]["wp:featuredmedia"][0]["source_url"],
            ),
            new Text(post['content']['rendered'].replaceAll(new RegExp(r'<[^>]*>'), ''))
          ],
        ),
      ),
    );
  }
}



Share with your friends