Create a Twitter Home Screen and Slide Menu

Published by @SoNiceInfo at 6/24/2020


Xcode making a Twitter home screen

I'll show you how to create a Twitter home screen and slide menu with SwiftUI.
Use gesture and DragGesture to swipe to the right to bring up the slide menu. To show or hide the slide menu, change the value of the horizontal offset.

I'll break down the home screen into the following elements and show you how to make them in order

Menu (Orange frame)

MenuView.swift

Title Bar & Tab (Blue frame)

MainView.swift

Timeline (Green frame)

TimelineView.swift

Combine

Implementing swipe here

ContentView.swift
An image of the Twitter home screen broken down into elements

First, let's prepare the menu. Here, we implement the contents of the View.
The swiping part is implemented in ContentView.swift.

//
//  MenuView.swift
//

import SwiftUI

struct MenuView: View {

    var body: some View {
        VStack(alignment: .leading) {
            Image("animal_kuma")
                .resizable()
                .overlay(
                    Circle().stroke(Color.gray, lineWidth: 1))
                .frame(width: 60, height: 60)
                .clipShape(Circle())
            Text("SwiftUIへの道")
                .font(.largeTitle)
            Text("@road2swiftui")
                .font(.caption)
            Divider()
            ScrollView (.vertical, showsIndicators: true) {
                HStack {
                    Image(systemName: "person")
                    Text("Profile")
                }
                HStack {
                    Image(systemName: "list.dash")
                    Text("Lists")
                }
                HStack {
                    Image(systemName: "text.bubble")
                    Text("Topics")
                }
            }
            Divider()
            Text("Settings and privacy")
        }
        .padding(.horizontal, 20)
    }
}


struct MenuView_Previews: PreviewProvider {
    static var previews: some View {
        MenuView()
    }
}
The screen where the MenuView was created

Title Bar & Tab (Blue frame) - MainView.swift

Create Title Bar and Tab with combining NavigationView and TabView.
The font size and background color of the title bar cannot be changed directly in the SwiftUI.
Use UINavigationBar.appearance() and UITabBar.appearance() in the initializer.

//
//  MainView.swift
//

import SwiftUI

struct MainView: View {
    
    init() {
        // Change the font size of the title bar.
        UINavigationBar.appearance().titleTextAttributes = [.font: UIFont.systemFont(ofSize: 26)]
        // Change the background color of the title bar.
        UINavigationBar.appearance().barTintColor = UIColor.white
        // Change the background color behind the title bar.
        UINavigationBar.appearance().backgroundColor = UIColor.white
        // Change the background color of the tab bar.
        UITabBar.appearance().barTintColor = UIColor.white
        // Change the background color behind the tab bar.
        UITabBar.appearance().backgroundColor = UIColor.white
    }
    
    var body: some View {
        TabView {
            NavigationView {
                ScrollView (.vertical, showsIndicators: false) {
                    // This part is implemented in the next section.
                    TimelineView(timelines: timelines)
                }
                    // Specify the title and left and right icons.
                    .navigationBarTitle(Text("🐥"), displayMode: .inline)
                    .navigationBarItems(
                        leading: Image("animal_kuma")
                            .resizable()
                            .overlay(
                                Circle().stroke(Color.gray, lineWidth: 1))
                            .frame(width: 30, height: 30)
                            .clipShape(Circle()),
                        trailing: HStack{
                            IconView(systemName: "sparkles")
                        }
                        .padding(.bottom, 10)
                    )
                }
                .tabItem {
                    IconView(systemName: "house")
                }
            IconView(systemName: "magnifyingglass")
                .tabItem {
                    IconView(systemName: "magnifyingglass")
                }
            IconView(systemName: "bell")
                .tabItem {
                    IconView(systemName: "bell")
                }
            IconView(systemName: "envelope")
                .tabItem {
                    IconView(systemName: "envelope")
                }
        }
        // Change the color of the selected icon to blue.
        .accentColor(.blue)
    }
}

// Consistent Icon Formats
struct IconView: View {
    var systemName: String

    var body: some View {
        Image(systemName: systemName)
            .font(.title)
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()
    }
}
The result of reproducing the title bar and tabs on the home screen

Timeline (Green frame) - TimelineView.swift

Creating template with struct Timeline, define mock with let timelines: [Timeline].
Use ForEach to display timelines one by one.

//
//  TimelineView.swift
//

import SwiftUI

struct Timeline {
    let id: Int
    let name: String
    let image: String
    let post: String
    let post_image: String
}

let timelines: [Timeline] = [
    Timeline(id: 0, name: "Arupaka", image: "animal_arupaka", post: "This is post content", post_image: "ice_1"),
    Timeline(id: 1, name: "Buta", image: "animal_buta", post: "This is post content", post_image: "ice_2"),
    Timeline(id: 2, name: "Hamster", image: "animal_hamster", post: "This is post content", post_image: "flower"),
    Timeline(id: 3, name: "Hiyoko", image: "animal_hiyoko", post: "This is post content", post_image: "moon"),
    Timeline(id: 4, name: "Inu", image: "animal_inu", post: "This is post content", post_image: "animal_inu")
]

struct TimelineView: View {
    let timelines: [Timeline]

    var body: some View {
        VStack() {
            ForEach(self.timelines, id: \.id) { (timeline) in
                VStack(spacing: 5) {
                    HStack(alignment: .top) {
                        Image(timeline.image)
                            .resizable()
                            .clipShape(Circle())
                            .overlay(
                                Circle().stroke(Color.white, lineWidth: 4))
                            .frame(width: 60, height: 60, alignment: .leading)
                        VStack(alignment: .leading) {
                            HStack {
                                Text(timeline.name)
                                    .fontWeight(.bold)
                                Text("@\(timeline.name)")
                                    .foregroundColor(.gray)
                            }
                            Text(timeline.post)
                            Image(timeline.post_image)
                                .resizable()
                                .scaledToFill()
                                .frame(height: 200)
                                .cornerRadius(20)
                        }
                    }
                    .padding(.horizontal, 10)
                    Divider()
                }
            }
        }
    }
}

struct TimelineView_Previews: PreviewProvider {
    static var previews: some View {
        TimelineView(timelines: timelines)
    }
}
The screen where you created your TimelineView

Combine - ContentView.swift

Display the MenuView and MainView with HStack.
Change offset in the horizontal direction to show or hide the slide menu.
You can retrive the swipe distance with value.translation.width.

//
//  ContentView.swift
//

import SwiftUI

struct ContentView: View {
    // Preserves the horizontal offset of the screen in the xOffset variable.
    @State private var xOffset = CGFloat.zero
    @State private var defaultOffset = CGFloat.zero
    
    var body: some View {
        // Use GeometoryReader to get the screen size
        GeometryReader { geometry in
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 0) {
                    MenuView()
                        // Width should be 70% of the screen size
                        .frame(width: geometry.size.width * 0.7)
                    Divider()
                    MainView()
                        // Width should be 100% of the screen size
                        .frame(width: geometry.size.width)
                }
                // First, minus the value of the screen offset by the slide menu.
                .onAppear(perform: {
                    self.xOffset = geometry.size.width * -0.7
                    self.defaultOffset = self.xOffset
                })
                .offset(x: self.xOffset)
                // Specify the screen size.
                .frame(width: geometry.size.width, alignment: .leading)
                // Set the animation of the slide.
                .animation(.default)
                // Detects gesture-related events.
                .gesture(
                    // Detects events related to dragging, i.e., sliding and swiping
                    DragGesture()
                        // Implements the movement when a swipe is detected
                        .onChanged{ value in
                            // Dynamically changes the offset value when the swipe distance is greater than 5
                            // Exceeding the threshold (5 in this case) will give you real-time movement
                            if (self.xOffset != .zero && value.translation.width > 5) {
                                self.xOffset = self.defaultOffset + value.translation.width
                            }
                        }
                        // Implement the movement when the swipe is finished
                        .onEnded { value in
                            // If the swipe distance to the right is greater than 5, set the offset to 0
                            // i.e. display the menu
                            // Otherwise, set the offset to the slide menu
                            // i.e. hide the slide menu
                            if (value.translation.width > 5) {
                                self.xOffset = .zero
                            } else {
                                self.xOffset = self.defaultOffset
                            }
                        }
                    )
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

素材

かわいいフリー素材集 いらすとや
Beautiful Free Images & Pictures | Unsplash

    I released iOS App!

    ToDo App

    Visualize Activity, Data sharing with iCloud, Dark mode supported.

    リリースしたToDoアプリのスクリーンショット

    IP Address bookmark.

    Check and bookamrk IP address of all interfaces with geolocation.

    リリースしたIPアドレス保存アプリのスクリーンショット