Mobile Development 16 min read

From Zero to Flutter Demo: Building a Penguin Tutor App Sample

This article walks through the author’s hands‑on experience creating a Flutter‑based sample of the Penguin Tutor app, covering project setup, UI layout, routing, event handling, dependency management, and code snippets, while reflecting on lessons learned and best‑practice recommendations.

Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
From Zero to Flutter Demo: Building a Penguin Tutor App Sample

Introduction

The Tencent Online Education team (OED) has deployed Flutter in the "Penguin Tutor" product, and the IMWeb team joined to push product rollout and technical improvement. The author used a holiday break to build a Flutter sample project from scratch, aiming to understand the development workflow, debugging, UI layout, events, and basic capabilities.

Purpose of the Sample Project

The goal is to become familiar with Flutter's development process, identify pain points, and lay groundwork for future engineering and dynamic operation improvements.

Development Experience

Starting with little knowledge, the author explored component usage, UI reconstruction, and routing. They noted that writing Dart feels different from JavaScript, and that Flutter's layout can be thought of as "CSS in JS". The sample includes three primary pages and a basic demo, with many features simplified for learning purposes.

Key Observations

Flutter UI can achieve high fidelity when ported to web, making partial commercial use feasible.

Writing clean, well‑structured code and establishing coding standards greatly improves development efficiency.

Understanding component hierarchy, routing, and event handling is essential for maintainable apps.

Code Samples

import 'dart:convert';
import 'package:meta/meta.dart';

class SysCourse {
  final String title; // title
  final String timeArea; // class time
  SysCourse({this.timeArea, this.title});
  static List<SysCourse> fromJson(String json) {
    List<SysCourse> _sysCourseList = [];
    JsonDecoder decoder = new JsonDecoder();
    var mapdata = decoder.convert(json)['List'];
    mapdata.forEach((item) {
      SysCourse obj = new SysCourse(
        timeArea: item['time_area'],
        title: item['title'],
      );
      _sysCourseList.add(obj);
    });
    return _sysCourseList;
  }
}

var sys = new SysCourse(title: '高一秋季系统课', timeArea: '9月10-12月26日');
class Person {
  String firstName;
  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});
  if (emp is Person) {
    emp.firstName = 'Bob';
  } else {
    (emp as Person).firstName = 'Bob';
  }
}
@override
Widget build(BuildContext context) {
  Map<String, WidgetBuilder> routes = {
    'pack': (context) => CoursePack(),
    'my': (context) => My(),
    'break': (context) => Break(),
    'router': (context) => DiscoverRouter(),
    'grade': (context) => Grade(),
    'discover': (context) => Discover()
  };
  return MaterialApp(
    title: '企鹅辅导',
    theme: ThemeData(primaryColor: Colors.white, primarySwatch: Colors.blue),
    debugShowCheckedModeBanner: false,
    home: SplashPage(),
    routes: routes,
    navigatorObservers: [routeObserver],
  );
}
GestureDetector(
  child: Container(
    margin: EdgeInsets.all(10.0),
    child: ClipRRect(
      borderRadius: BorderRadius.circular(5.0),
      child: Image.asset(item, fit: BoxFit.cover),
    ),
  ),
  onTap: () {
    print('轮播图点击');
    Navigator.pushNamed(context, 'webView');
  },
);

Event Bus and Communication

EventBus eventBus = new EventBus();
class TransEvent {
  String text;
  TransEvent(this.text);
}

eventBus.fire(TransEvent('gradeRouter'));

eventBus.on<TransEvent>().listen((data) => change(data.text));

Lifecycle Management

class Foo extends StatefulWidget {
  @override
  _FooState createState() => _FooState();
}

class _FooState extends State<Foo> {
  StreamSubscription streamSubscription;
  @override
  void initState() {
    super.initState();
    streamSubscription = Bloc.of(context).myStream.listen((value) {
      print(value);
    });
  }
  @override
  void dispose() {
    streamSubscription.cancel();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

Conclusion

Flutter to App or Web can achieve high visual fidelity, and with careful handling it can be used in certain commercial scenarios. The author emphasizes the importance of coding standards, modular architecture, and continuous learning to improve development efficiency and product quality.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DARTMobile DevelopmentUIroutingCode Samplesevent bus
Tencent IMWeb Frontend Team
Written by

Tencent IMWeb Frontend Team

IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.