SwiftUI实战系列
- SwiftUI实战-使用ViewModifier自定义微信TabBar底部导航和NavigationView
- SwiftUI实战-NavigationLink图片和文字显示蓝色或者图片无显示
- SwiftUI实战-去除List分割线
- SwiftUI实战-自定义弹窗
- SwiftUI实战-自定义加载指示器HUD
- SwiftUI实战-广告页、欢迎页
- SwiftUI实战-NavigationView + TabView基本框架搭建
- SwiftUI实战-Pager分页查看器
- SwiftUI实战-隐私政策和用户协议弹窗
- SwiftUI实战-多图、大图图片浏览
- SwiftUI实战-下拉菜单
- SwiftUI实战-系统NavigationView自定义titleView
- SwiftUI实战-WKWebView的使用
- SwiftUI实战-自定义转圈指示器
- SwiftUI实战-自定义TextField搭建登录页面UI
- SwiftUI实战-自定义底部弹窗
- SwiftUI实战-显示星级评分
- SwiftUI实战-类似新闻头条轮播滚动
- SwiftUI实战-仿用户协议确认页面支持点击文字显示协议
- SwiftUI实战-新特性、新版本介绍
- SwiftUI实战-多图选择、图片选择器
- SwiftUI实战-轮播图
- SwiftUI实战-网络请求工具封装
- SwiftUI实战-多级联动地址选择
- SwiftUI实战-使用UIActivityIndicatorView
- SwiftUI实战-Expanded可伸缩的分组列表List
- SwiftUI实战-滚动列表内容返回顶部、底部、指定位置
- SwiftUI实战-List列表内容动态改变更新
- SwiftUI-绘制气泡图
- SwiftUI-仿微信加号Popover气泡弹窗
- SwiftUI实战-单边圆角单个圆角
本章内容
实现登录页面UI基本搭建
效果图:

自定义TextField.gif
将学到的内容:
1、实现密码输入的SecureField模式
2、监听输入框的内容变化
3、输入限制字数输入
4、ViewModifier的拓展使用
5、PreferenceKey 传值使用
相关源码如下:
LoginView.swift
import SwiftUI
struct LoginView: View {
//@EnvironmentObject var lauchViewVM: LauchViewModel
@Environment(\.presentationMode) var presentationMode
@State var account: String = ""
@State var password: String = ""
@State var content: String?
@State var attributedText: NSAttributedString?
@State var isSecureField = true
@State var isShowClear = false
var body: some View {
/*
// 输入监听
let binding = Binding<String>(get: {
self.account
}, set: {
debugPrint($0)
self.account = $0
})
*/
VStack {
VStack {
HStack {
Text("账号:").padding(.horizontal, 10)
Spacer().frame(width: 0)
CSInputTextField.init(placeholder: "请输入账号", text: $account) { value in
//debugPrint(value)
}
.frame(height: 40)
.overlay(
RoundedRectangle(cornerRadius: 5, style: .continuous)
.stroke(.orange, lineWidth: 1.0)
)
}
/*
HStack {
CSSTextView.init(placeholder: "请输入内容", attributedText: $attributedText, onCommit: { value in
debugPrint(value)
})
.frame(height: 100)
.overlay(
RoundedRectangle(cornerRadius: 5, style: .continuous)
.stroke(.orange, lineWidth: 1.0)
)
}
*/
HStack {
Text("密码:").padding(.horizontal, 10)
Spacer().frame(width: 0)
ZStack {
CSInputTextField.init(placeholder: "请输入密码", text: $password, isSecureField: isSecureField) { value in
debugPrint(value)
}
.frame(height: 40)
.preference(key: CustomPreferenceKey<String>.self, value: password)
.onPreferenceChange (CustomPreferenceKey<String>.self) { value in
// 只能传到上一级的父组件
debugPrint(value)
if value.count > 6 {
password = String(value.prefix(6))
}
isShowClear = value.count > 0
}
HStack {
Spacer()
if isShowClear {
Image.init(systemName: "xmark")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(.trailing, 10)
.frame(width: 20, height: 20)
.onTapGesture {
password = ""
}
}
/*
Text(isSecureField ? "查看" : "隐藏")
.padding(.leading, 5)
.padding(.trailing, 5)
.onTapGesture {
isSecureField.toggle()
}
*/
}
}
.overlay(
RoundedRectangle(cornerRadius: 5, style: .continuous)
.stroke(.orange, lineWidth: 1.0)
)
}
HStack {
Button.init {
} label: {
Text("登录")
.foregroundColor(Color.white)
.frame(maxWidth: .infinity, minHeight: 45, maxHeight: 45)
.background(Color.orange)
.cornerRadius(5)
.overlay(
RoundedRectangle(cornerRadius: 5, style: .continuous)
.stroke(.orange, lineWidth: 1.0)
)
}
}
.frame(maxWidth: .infinity, minHeight: 45, maxHeight: 45)
}
.padding(.top, 50)
.padding(.horizontal, 20)
Spacer()
}
.navigationBarTitle("登录", displayMode: .inline)
.navigationBarItems(trailing: Button.init(action: {
}, label: {
NavigationLink.init(destination: RegisterView()) {
Text("注册")
}
}))
}
}
CSInputTextField.swift