← Back to list

Complete KivyMD WhatsApp UI Tutorial: Building Mobile Apps with Python

Introduction

Opeyemi Abubakry · 2025-07-13 04:48 · 0 claps · 7.2 min read paywalled
#kivymd #kivy #kivy-python #kivy-tutorial #python-app-development
Open on Medium ↗
Wiki topics: 📱 · Mobile Development

Complete KivyMD WhatsApp UI Tutorial: Building Mobile Apps with Python

Introduction

KivyMD is a powerful extension of the Kivy framework that brings Material Design components to Python mobile app development. While there’s a scarcity of comprehensive KivyMD tutorials online, this guide will take you through building a complete WhatsApp UI redesign, providing you with the knowledge to create stunning mobile applications.

This tutorial assumes you have basic knowledge of Python programming and some familiarity with the Kivy framework. We’ll start from the ground up and build a fully functional WhatsApp-style interface.

What You’ll Learn

  • Setting up a KivyMD application structure
  • Implementing Material Design theming
  • Creating responsive mobile UI layouts
  • Working with KivyMD widgets and components
  • Building a complete chat interface
  • Customizing colors and themes

Prerequisites

Before we begin, ensure you have the following installed:

Required Software

  • Python 3.7 or higher
  • pip (Python package installer)
  • A code editor (VS Code, PyCharm, or similar)

Installation

Install the required packages:

# Install KivyMD (this will also install Kivy)
pip install kivymd
# For better development experience, also install:
pip install kivy[base] kivymd[dev]

Verify Installation

Create a test file to verify everything is working:

# test_installation.py
try:
    import kivy
    import kivymd
    print("✓ Kivy and KivyMD installed successfully!")
    print(f"Kivy version: {kivy.__version__}")
    print(f"KivyMD version: {kivymd.__version__}")
except ImportError as e:
    print(f"Installation error: {e}")

Understanding KivyMD vs Kivy

KivyMD extends Kivy with Material Design components, offering:

  • Material Design Widgets: Buttons, cards, navigation drawers, etc.
  • Theming System: Consistent color schemes and typography
  • Responsive Design: Automatic adaptation to different screen sizes
  • Modern UI Components: Following Google’s Material Design guidelines

Building the Basic Application Structure

Step 1: Create the Main Application File

Create a new file called main.py:

# main.py
import kivy
from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from kivy.core.window import Window

# Set window size for mobile simulation
Window.size = (320, 600)

class WhatsAppClone(MDApp):
    """
    Main application class for WhatsApp UI clone
    Inherits from MDApp to get Material Design functionality
    """

    def build(self):
        """
        Initializes the application and returns the root widget
        This method is called once when the app starts
        """
        # Set up the app theme
        self.setup_theme()

        # Set window title
        self.title = "WhatsApp"

        # Return the root widget (for now, just a simple label)
        return MDLabel(
            text="WhatsApp UI Clone",
            halign="center",
            theme_text_color="Primary"
        )

    def setup_theme(self):
        """
        Configure the app's theme colors and style
        """
        # Set theme style (Dark or Light)
        self.theme_cls.theme_style = "Dark"

        # Set primary color palette
        self.theme_cls.primary_palette = "Teal"

        # Set accent color palette (for highlights and accents)
        self.theme_cls.accent_palette = "Teal"

        # Set accent hue for lighter teal color
        self.theme_cls.accent_hue = "400"

# Run the application
if __name__ == "__main__":
    WhatsAppClone().run()

Understanding the Code Structure

Let’s break down each component:

Import Statements

import kivy                    # Core Kivy framework
from kivymd.app import MDApp   # Material Design app class
from kivymd.uix.label import MDLabel  # Material Design label widget
from kivy.core.window import Window   # Window management

Window Configuration

Window.size = (320, 600)  # Set window size (width, height) in pixels

This simulates a mobile device screen size for development purposes.

App Class Definition

class WhatsAppClone(MDApp):

We inherit from MDApp instead of Kivy's App to get Material Design functionality.

The build() Method

The build() method is crucial - it:

  1. Runs once when the app starts
  2. Sets up the theme
  3. Configures the window title
  4. Returns the root widget of the application

Understanding KivyMD Theming System

Available Color Palettes

KivyMD provides predefined color palettes based on Material Design:

# Available color palettes
PALETTES = [
    'Red', 'Pink', 'Purple', 'DeepPurple', 'Indigo', 'Blue', 
    'LightBlue', 'Cyan', 'Teal', 'Green', 'LightGreen', 'Lime', 
    'Yellow', 'Amber', 'Orange', 'DeepOrange', 'Brown', 'Gray', 'BlueGray'
]

Hue Values

Each palette has multiple hue variations:

# Available hue values
HUES = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700']

Theme Configuration Explained

def setup_theme(self):
    # Theme style: "Light" or "Dark"
    self.theme_cls.theme_style = "Dark"

    # Primary palette: Main app color
    self.theme_cls.primary_palette = "Teal"

    # Accent palette: Secondary color for highlights
    self.theme_cls.accent_palette = "Teal"

    # Accent hue: Lighter variation of the accent color
    self.theme_cls.accent_hue = "400"

Building a Complete WhatsApp Interface

Now let’s create a more complete WhatsApp-style interface:

# complete_whatsapp_ui.py
import kivy
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.toolbar import MDTopAppBar
from kivymd.uix.list import MDList, OneLineListItem, TwoLineListItem, ThreeLineListItem
from kivymd.uix.list import OneLineIconListItem, TwoLineIconListItem
from kivymd.uix.scrollview import MDScrollView
from kivymd.uix.textfield import MDTextField
from kivymd.uix.button import MDIconButton, MDFloatingActionButton
from kivymd.uix.card import MDCard
from kivymd.uix.label import MDLabel
from kivymd.uix.screen import MDScreen
from kivymd.uix.screenmanager import MDScreenManager
from kivymd.uix.bottomnavigation import MDBottomNavigation, MDBottomNavigationItem
from kivymd.uix.tab import MDTabs, MDTabsBase
from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.icon_definitions import md_icons
from kivy.core.window import Window
from kivy.metrics import dp

# Set window size for mobile simulation
Window.size = (320, 600)

class ChatListItem(TwoLineIconListItem):
    """Custom list item for chat conversations"""

    def __init__(self, contact_name, last_message, time, avatar_icon="account", **kwargs):
        super().__init__(**kwargs)
        self.text = contact_name
        self.secondary_text = last_message
        self.tertiary_text = time

        # Add avatar icon
        self.add_widget(
            MDIconButton(
                icon=avatar_icon,
                theme_icon_color="Custom",
                icon_color=self.theme_cls.primary_color,
                pos_hint={"center_y": 0.5},
                on_release=self.open_chat
            )
        )

    def open_chat(self, instance):
        """Handle chat opening"""
        print(f"Opening chat with {self.text}")

class ChatsTab(MDFloatLayout):
    """Tab containing chat conversations"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.create_chat_list()

    def create_chat_list(self):
        """Create the list of chat conversations"""

        # Create scroll view for chat list
        scroll = MDScrollView()
        chat_list = MDList()

        # Sample chat data
        chats = [
            ("John Doe", "Hey, how are you doing?", "2:30 PM", "account"),
            ("Jane Smith", "See you tomorrow!", "1:45 PM", "account-circle"),
            ("Family Group", "Mom: Don't forget dinner", "12:30 PM", "account-group"),
            ("Work Team", "Meeting at 3 PM", "11:15 AM", "briefcase"),
            ("Sarah Wilson", "Thanks for the help!", "10:20 AM", "account-heart"),
            ("Mike Johnson", "Call me when you're free", "Yesterday", "phone"),
            ("Study Group", "Assignment due tomorrow", "Yesterday", "school"),
            ("Alex Brown", "Great job on the project!", "Monday", "thumb-up"),
        ]

        # Add chat items to the list
        for contact, message, time, icon in chats:
            chat_item = ChatListItem(
                contact_name=contact,
                last_message=message,
                time=time,
                avatar_icon=icon
            )
            chat_list.add_widget(chat_item)

        scroll.add_widget(chat_list)
        self.add_widget(scroll)

        # Add floating action button for new chat
        fab = MDFloatingActionButton(
            icon="message-plus",
            pos_hint={"center_x": 0.85, "center_y": 0.15},
            on_release=self.new_chat
        )
        self.add_widget(fab)

    def new_chat(self, instance):
        """Handle new chat creation"""
        print("Creating new chat")

class StatusTab(MDFloatLayout):
    """Tab for status updates"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.create_status_list()

    def create_status_list(self):
        """Create the list of status updates"""

        scroll = MDScrollView()
        status_list = MDList()

        # Add "My Status" item
        my_status = TwoLineIconListItem(
            text="My Status",
            secondary_text="Tap to add status update",
            on_release=self.add_status
        )
        my_status.add_widget(
            MDIconButton(
                icon="plus-circle",
                theme_icon_color="Custom",
                icon_color=self.theme_cls.primary_color,
                pos_hint={"center_y": 0.5}
            )
        )
        status_list.add_widget(my_status)

        # Add divider
        status_list.add_widget(MDLabel(text="Recent updates", size_hint_y=None, height=dp(40)))

        # Sample status updates
        statuses = [
            ("Alice Cooper", "25 minutes ago", "camera"),
            ("Bob Wilson", "1 hour ago", "video"),
            ("Carol Johnson", "3 hours ago", "camera"),
            ("David Smith", "5 hours ago", "video"),
        ]

        for name, time, icon in statuses:
            status_item = TwoLineIconListItem(
                text=name,
                secondary_text=time,
                on_release=lambda x, name=name: self.view_status(name)
            )
            status_item.add_widget(
                MDIconButton(
                    icon=icon,
                    theme_icon_color="Custom",
                    icon_color=self.theme_cls.accent_color,
                    pos_hint={"center_y": 0.5}
                )
            )
            status_list.add_widget(status_item)

        scroll.add_widget(status_list)
        self.add_widget(scroll)

    def add_status(self, instance):
        """Handle status addition"""
        print("Adding new status")

    def view_status(self, name):
        """Handle status viewing"""
        print(f"Viewing status from {name}")

class CallsTab(MDFloatLayout):
    """Tab for call history"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.create_call_list()

    def create_call_list(self):
        """Create the list of call history"""

        scroll = MDScrollView()
        call_list = MDList()

        # Sample call data
        calls = [
            ("John Doe", "Today, 2:30 PM", "call-made", "green"),
            ("Jane Smith", "Today, 1:45 PM", "call-received", "green"),
            ("Mike Johnson", "Yesterday, 8:20 PM", "call-made", "green"),
            ("Sarah Wilson", "Yesterday, 3:15 PM", "call-missed", "red"),
            ("Work Team", "Monday, 10:30 AM", "video", "blue"),
            ("Mom", "Sunday, 7:45 PM", "call-received", "green"),
        ]

        for name, time, call_type, color in calls:
            call_item = TwoLineIconListItem(
                text=name,
                secondary_text=time,
                on_release=lambda x, name=name: self.make_call(name)
            )
            call_item.add_widget(
                MDIconButton(
                    icon=call_type,
                    theme_icon_color="Custom",
                    icon_color=color,
                    pos_hint={"center_y": 0.5}
                )
            )
            call_list.add_widget(call_item)

        scroll.add_widget(call_list)
        self.add_widget(scroll)

    def make_call(self, name):
        """Handle call initiation"""
        print(f"Calling {name}")

class MainScreen(MDScreen):
    """Main screen with tabs"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.create_interface()

    def create_interface(self):
        """Create the main interface with toolbar and tabs"""

        # Main layout
        main_layout = MDBoxLayout(orientation="vertical")

        # Top toolbar
        toolbar = MDTopAppBar(
            title="WhatsApp",
            md_bg_color=self.theme_cls.primary_color,
            specific_text_color="white",
            right_action_items=[
                ["magnify", lambda x: self.search()],
                ["dots-vertical", lambda x: self.show_menu()],
            ]
        )

        # Tabs
        tabs = MDTabs(
            tab_hint_x=True,
            tab_hint_y=True,
            background_color=self.theme_cls.primary_color,
            indicator_color=self.theme_cls.accent_color,
            text_color_active="white",
            text_color_normal="white"
        )

        # Add tabs
        chats_tab = MDBottomNavigationItem(
            name="chats",
            text="CHATS",
            icon="message-text"
        )
        chats_tab.add_widget(ChatsTab())

        status_tab = MDBottomNavigationItem(
            name="status",
            text="STATUS",
            icon="circle-slice-8"
        )
        status_tab.add_widget(StatusTab())

        calls_tab = MDBottomNavigationItem(
            name="calls",
            text="CALLS",
            icon="phone"
        )
        calls_tab.add_widget(CallsTab())

        tabs.add_widget(chats_tab)
        tabs.add_widget(status_tab)
        tabs.add_widget(calls_tab)

        # Add components to main layout
        main_layout.add_widget(toolbar)
        main_layout.add_widget(tabs)

        self.add_widget(main_layout)

    def search(self):
        """Handle search functionality"""
        print("Search activated")

    def show_menu(self):
        """Handle menu display"""
        print("Menu opened")

class WhatsAppClone(MDApp):
    """Main application class"""

    def build(self):
        """Build the application"""

        # Set up theme
        self.setup_theme()

        # Set window title
        self.title = "WhatsApp"

        # Create screen manager
        screen_manager = MDScreenManager()

        # Add main screen
        main_screen = MainScreen(name="main")
        screen_manager.add_widget(main_screen)

        return screen_manager

    def setup_theme(self):
        """Configure the app theme"""

        # Set theme style
        self.theme_cls.theme_style = "Dark"

        # Set primary color (main app color)
        self.theme_cls.primary_palette = "Teal"

        # Set accent color (for highlights)
        self.theme_cls.accent_palette = "Teal"
        self.theme_cls.accent_hue = "400"

        # Additional theme customizations
        self.theme_cls.material_style = "M3"  # Material Design 3

# Run the application
if __name__ == "__main__":
    WhatsAppClone().run()

Key Features Explained

1. Custom List Items

class ChatListItem(TwoLineIconListItem):

We create custom list items that inherit from KivyMD’s TwoLineIconListItem, allowing us to display contact names, last messages, and avatars.

2. Tabbed Interface

tabs = MDTabs(
    tab_hint_x=True,
    tab_hint_y=True,
    background_color=self.theme_cls.primary_color,
    indicator_color=self.theme_cls.accent_color,
)

The tabs provide navigation between Chats, Status, and Calls sections.

3. Floating Action Button

fab = MDFloatingActionButton(
    icon="message-plus",
    pos_hint={"center_x": 0.85, "center_y": 0.15},
    on_release=self.new_chat
)

Material Design floating action button for primary actions.

4. Responsive Layout

The layout automatically adapts to different screen sizes using KivyMD’s responsive design principles.

Advanced Customization

Custom Color Scheme

def setup_custom_theme(self):
    """Set up a custom color scheme"""

    # Use custom colors
    self.theme_cls.primary_palette = "Green"
    self.theme_cls.primary_hue = "700"  # WhatsApp's actual green

    self.theme_cls.accent_palette = "LightGreen"
    self.theme_cls.accent_hue = "400"

    # Set custom background colors
    self.theme_cls.bg_dark = "#0D1117"
    self.theme_cls.bg_light = "#FFFFFF"

Adding Icons and Images

# Add custom avatars
avatar = MDIconButton(
    icon="account-circle",
    theme_icon_color="Custom",
    icon_color=self.theme_cls.primary_color,
    icon_size="40dp"
)

Animation and Transitions

from kivy.animation import Animation
def animate_fab(self, instance):
    """Animate floating action button"""
    anim = Animation(size=(dp(60), dp(60)), duration=0.2)
    anim.start(instance)

Testing and Debugging

Running the Application

python main.py

Common Issues and Solutions

  1. Import Errors: Ensure KivyMD is properly installed
  2. Window Size: Adjust Window.size for different screen sizes
  3. Theme Issues: Check palette names and hue values
  4. Layout Problems: Use MDBoxLayout and MDFloatLayout appropriately

Development Tips

  1. Use MDScreen: For complex layouts, use MDScreen containers
  2. Theme Consistency: Stick to Material Design principles
  3. Testing: Test on different screen sizes and orientations
  4. Performance: Use MDList for long lists of items

Next Steps

  1. Add Navigation: Implement screen navigation between chats
  2. Database Integration: Store chat messages and contacts
  3. Real-time Updates: Add WebSocket support for live messaging
  4. Media Support: Add image and video message support
  5. Notifications: Implement push notifications
  6. Deployment: Package for Android/iOS using Buildozer

Conclusion

This tutorial has provided you with a comprehensive foundation for building mobile applications with KivyMD. You’ve learned how to:

  • Set up a KivyMD application with proper theming
  • Create responsive layouts using Material Design components
  • Implement tabbed navigation and custom list items
  • Handle user interactions and events
  • Customize the appearance with themes and colors

The WhatsApp UI clone demonstrates the power and flexibility of KivyMD for creating professional mobile applications. With this foundation, you can extend the app with additional features like real messaging, user authentication, and media sharing.

Remember that building great mobile apps is an iterative process. Start with a solid foundation like this tutorial provides, then gradually add features and improvements based on user feedback and requirements.


메타데이터
post_id
2f6b8c60cae7
slug
complete-kivymd-whatsapp-ui-tutorial-2f6b8c60cae7
url
https://medium.com/@haddiebakrie/complete-kivymd-whatsapp-ui-tutorial-2f6b8c60cae7
canonical_url
https://medium.com/@haddiebakrie/complete-kivymd-whatsapp-ui-tutorial-2f6b8c60cae7
author_url
https://medium.com/@haddiebakrie
status
ok
fetched_at
2026-07-19 00:45:20