Android page development tutorial similar to WeChat homepage (Kotlin) II

prerequisite

Install and configure Android Studio

Android Studio Electric Eel | 2022.1.1 Patch 2
Build #AI-221.6008.13.2211.9619390, built on February 17, 2023
Runtime version: 11.0.15+0-b2043.56-9505619 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 11 10.0
GC: G1 Young Generation, G1 Old Generation
Memory: 1280M
Cores: 6
Registry:
    external.system.auto.import.disabled=true
    ide.text.editor.with.preview.show.floating.toolbar=false
    ide.balloon.shadow.size=0
 
Non-Bundled Plugins:
    com.intuit.intellij.makefile (1.0.15)
    com.github.setial (4.0.2)
    com.alayouni.ansiHighlight (1.2.4)
    GsonOrXmlFormat (2.0)
    GLSL (1.19)
    com.mistamek.drawablepreview.drawable-preview (1.1.5)
    com.layernet.plugin.adbwifi (1.0.5)
    com.likfe.ideaplugin.eventbus3 (2020.0.2)

gradle-wrapper.properties

#Tue Apr 25 13:34:44 CST 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

build.gradle(:Project)

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    id 'com.android.application' version '7.3.1' apply false
    id 'com.android.library' version '7.3.1' apply false
    id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
}

setting.gradle

pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
        maven { url 'https://jitpack.io' }
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
        maven { url 'https://jitpack.io' }
    }
}
rootProject.name = "logindemo"
include ':app'

build.gralde(:app)

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    namespace 'com.example.logindemo'
    compileSdk 33

    defaultConfig {
        applicationId "com.example.logindemo"
        minSdk 26
        targetSdk 33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.8.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    // 沉浸式状态栏 https://github.com/gyf-dev/ImmersionBar
    api 'com.gyf.immersionbar:immersionbar:3.0.0'
    api 'com.gyf.immersionbar:immersionbar-components:3.0.0' // fragment快速实现(可选)
    api 'com.gyf.immersionbar:immersionbar-ktx:3.0.0' // kotlin扩展(可选)
}

Basic understanding of the Kotlin language

The basic configuration was written in the previous blog. If you don’t understand the content of this article, you can go to the previous article first.

add title

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/titleTv"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="微信"
        android:textColor="#000000"
        android:textSize="20sp"
        android:gravity="center"
        android:background="@color/title"
        app:layout_constraintTop_toTopOf="parent"/>

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:tabIndicatorColor="@color/teal_200"
        app:tabSelectedTextColor="@color/teal_200"
        app:tabTextColor="@color/black" />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@+id/titleTv"
        app:layout_constraintBottom_toTopOf="@+id/tabLayout"/>

</androidx.constraintlayout.widget.ConstraintLayout>

After adding the title, when switching fragments, the corresponding title text needs to be changed

package com.example.logindemo

import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.example.logindemo.fragment.ChatFragment
import com.example.logindemo.fragment.ContactsFragment
import com.example.logindemo.fragment.DiscoverFragment
import com.google.android.material.tabs.TabLayout
import com.gyf.immersionbar.ImmersionBar

class MainActivity : AppCompatActivity() {

    private lateinit var viewPager: ViewPager
    private lateinit var tabLayout: TabLayout
    private lateinit var titleTv: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ImmersionBar.with(this)
            .statusBarDarkFont(true)
            .statusBarColor(R.color.title)
            .navigationBarColor(R.color.white)
            .navigationBarDarkIcon(true)
            .init()
        setContentView(R.layout.activity_main)
        val fragments = listOf(
            ChatFragment(),
            ContactsFragment(),
            DiscoverFragment()
        )
        titleTv = findViewById(R.id.titleTv)
        viewPager = findViewById(R.id.viewPager)
        tabLayout = findViewById(R.id.tabLayout)

        viewPager.adapter = ViewPagerAdapter(supportFragmentManager, fragments)
        tabLayout.setupWithViewPager(viewPager)

        tabLayout.getTabAt(0)?.text = "聊天"
        tabLayout.getTabAt(1)?.text = "联系人"
        tabLayout.getTabAt(2)?.text = "发现"

        tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
            override fun onTabSelected(tab: TabLayout.Tab?) {
                titleTv.text = tab?.text
            }

            override fun onTabUnselected(tab: TabLayout.Tab?) {

            }

            override fun onTabReselected(tab: TabLayout.Tab?) {

            }
        })
    }

    class ViewPagerAdapter(
        fragmentManager: androidx.fragment.app.FragmentManager,
        private val fragments: List<Fragment>
    ) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

        override fun getItem(position: Int): Fragment {
            return fragments[position]
        }

        override fun getCount(): Int {
            return fragments.size
        }
    }
}

modify fragment

Added RecyclerView to display multiple items in the layout

fragment_chat.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

fragment_contacts.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

fragment_discover.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

The content in the fragment is increased as follows

package com.example.logindemo.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.logindemo.R
import com.example.logindemo.base.BaseAdapter
import com.example.logindemo.bean.ChatBean

class ChatFragment : Fragment() {

    private lateinit var recyclerView: RecyclerView

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_chat, container, false)
        recyclerView = view.findViewById(R.id.recyclerView)
        val data = ArrayList<ChatBean>()
        data.add(ChatBean("头像0", "用户0", "聊天记录0", "4月25日"))
        data.add(ChatBean("头像1", "用户1", "聊天记录1", "4月24日"))
        data.add(ChatBean("头像2", "用户2", "聊天记录2", "4月23日"))
        data.add(ChatBean("头像3", "用户3", "聊天记录3", "4月22日"))
        data.add(ChatBean("头像4", "用户4", "聊天记录4", "4月21日"))
        data.add(ChatBean("头像5", "用户5", "聊天记录5", "4月20日"))
        data.add(ChatBean("头像6", "用户6", "聊天记录6", "4月19日"))
        data.add(ChatBean("头像7", "用户7", "聊天记录7", "4月18日"))
        data.add(ChatBean("头像8", "用户8", "聊天记录8", "4月17日"))
        data.add(ChatBean("头像9", "用户9", "聊天记录9", "4月16日"))
        recyclerView.layoutManager = LinearLayoutManager(context)
        recyclerView.adapter = BaseAdapter(data)
        return view
    }
}
package com.example.logindemo.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.logindemo.R
import com.example.logindemo.base.BaseAdapter
import com.example.logindemo.bean.ChatBean

class ContactsFragment : Fragment() {
    private lateinit var recyclerView: RecyclerView
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_contacts, container, false)
        recyclerView = view.findViewById(R.id.recyclerView)
        val data = ArrayList<ChatBean>()
        data.add(ChatBean("头像0", "用户0", "", ""))
        data.add(ChatBean("头像1", "用户1", "", ""))
        data.add(ChatBean("头像2", "用户2", "", ""))
        data.add(ChatBean("头像3", "用户3", "", ""))
        data.add(ChatBean("头像4", "用户4", "", ""))
        data.add(ChatBean("头像5", "用户5", "", ""))
        data.add(ChatBean("头像6", "用户6", "", ""))
        data.add(ChatBean("头像7", "用户7", "", ""))
        data.add(ChatBean("头像8", "用户8", "", ""))
        data.add(ChatBean("头像9", "用户9", "", ""))
        recyclerView.layoutManager = LinearLayoutManager(context)
        recyclerView.adapter = BaseAdapter(data)
        return view
    }
}
package com.example.logindemo.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.logindemo.R
import com.example.logindemo.base.BaseAdapter
import com.example.logindemo.bean.ChatBean

class DiscoverFragment : Fragment() {
    private lateinit var recyclerView: RecyclerView
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_discover, container, false)
        recyclerView = view.findViewById(R.id.recyclerView)
        val data = ArrayList<ChatBean>()
        data.add(ChatBean("头像0", "朋友圈", "", ""))
        data.add(ChatBean("头像1", "视频号", "", ""))
        data.add(ChatBean("头像2", "直播", "", ""))
        data.add(ChatBean("头像2", "扫一扫", "", ""))
        data.add(ChatBean("头像2", "摇一摇", "", ""))
        data.add(ChatBean("头像2", "看一看", "", ""))
        data.add(ChatBean("头像2", "搜一搜", "", ""))
        data.add(ChatBean("头像2", "附近", "", ""))
        data.add(ChatBean("头像2", "购物", "", ""))
        data.add(ChatBean("头像2", "游戏", "", ""))
        data.add(ChatBean("头像2", "小程序", "", ""))
        recyclerView.layoutManager = LinearLayoutManager(context)
        recyclerView.adapter = BaseAdapter(data)
        return view
    }
}

entry adapter

package com.example.logindemo.base

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.logindemo.R
import com.example.logindemo.bean.ChatBean

class BaseAdapter(private val data: List<ChatBean>) :
    RecyclerView.Adapter<BaseAdapter.BaseHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.base_item, null, false);
        return BaseHolder(view)
    }

    override fun getItemCount(): Int {
        return data.size
    }

    override fun onBindViewHolder(holder: BaseHolder, position: Int) {

        holder.headTv.visibility = if (data[position].head.isEmpty()) View.GONE else View.VISIBLE
        holder.nickTv.visibility = if (data[position].nick.isEmpty()) View.GONE else View.VISIBLE
        holder.newestTv.visibility = if (data[position].newest.isEmpty()) View.GONE else View.VISIBLE
        holder.dateTv.visibility = if (data[position].date.isEmpty()) View.GONE else View.VISIBLE

        holder.headTv.text = data[position].head
        holder.nickTv.text = data[position].nick
        holder.newestTv.text = data[position].newest
        holder.dateTv.text = data[position].date
    }

    class BaseHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val headTv: TextView = itemView.findViewById(R.id.headTv)
        val nickTv: TextView = itemView.findViewById(R.id.nickTv)
        val newestTv: TextView = itemView.findViewById(R.id.newestTv)
        val dateTv: TextView = itemView.findViewById(R.id.dateTv)
    }

}

type of data

package com.example.logindemo.bean

data class ChatBean(val head: String, val nick: String, val newest: String, val date: String) {

}

Guess you like

Origin blog.csdn.net/mozushixin_1/article/details/130366579