import SwiftUI
//Model and Model Data
struct Item1: Identifiable {
var id = UUID().uuidString // UUID 是一个结构体,表示“通用唯一标识符”
// uuidString 是 UUID 类型的一个属性,它返回该 UUID 的字符串表示形式。
var title: String
var price: String
var subTitle: String
var image: String
var offset: CGFloat = 0
}
import SwiftUI
struct TabBar: View {
@State var current = "Home"
var body: some View {
ZStack(alignment: Alignment(horizontal: .center, vertical: .bottom)) {
//Alignment 是一个结构体,允许你定义水平和垂直方向上的对齐方式。
TabView(selection: $current) {
Home()
.tag("Home")
Text("Message")
.tag("Message")
Text("Account")
.tag("Account")
}
HStack(spacing: 0) {
// TabButton
TabButton(title: "Home", image: "house", selected: $current)
Spacer(minLength: 0)
TabButton(title: "Message", image: "message", selected: $current)
Spacer(minLength: 0)
TabButton(title: "Account", image: "person", selected: $current)
}
.padding(.vertical, 12)
.padding(.horizontal)
.background(.black)
.clipShape(Capsule())
.padding(.horizontal, 25)
}
}
}
struct TabBar_Previews: PreviewProvider {
static var previews: some View {
TabBar()
}
}
import SwiftUI
struct Home: View {
@State var size = "Medium"
@State var currentTab = "All"
@State var items = [
Item1(title: "Coco Coffee", price: "$20.00", subTitle: "We have amazing Lamp wide range", image: "cat1"),
Item1(title: "Modern Coddee", price: "$60.00", subTitle: "We have amazing coffee", image: "cat1"),
Item1(title: "Common Coffee", price: "$35.00", subTitle: "Amazing quality width", image: "cat1"),
]
@GestureState var isDragging = false
// adding cart items
@State var cart: [Item1] = []
var body: some View {
VStack {
HStack {
Button {
}label: {
Image(systemName: "line.3.horizontal")
.font(.title)
.foregroundColor(.black)
}
Spacer()
Button {
}label: {
Image(systemName: "cart")
.font(.title)
.foregroundColor(.black)
}
.overlay(
// Cart Count
Text("\(cart.count)")
.font(.caption)
.foregroundColor(.white)
.fontWeight(.heavy)
.frame(width: 20, height: 20)
.background(.blue)
.clipShape(Circle())
.offset(x: 25, y: -22)
// disbling if no items
.opacity(cart.isEmpty ? 0 : 1)
)
}
.padding(.horizontal)
.padding(.top)
.padding(.bottom, 10)
ScrollView {
VStack {
HStack {
VStack(alignment: .leading, spacing: 8) {
Text("Welcome to \nMy Home")
.font(.largeTitle)
.fontWeight(.heavy)
.foregroundColor(.black)
Text("We have different coffees")
.font(.caption)
.foregroundColor(.gray)
.fontWeight(.bold)
}
Spacer(minLength: 15)
//minLength 是Spacer的一个参数,表示该空白空间的最小高度(或宽度,取决于容器的方向)
//minLength: 15 表示Spacer至少会占用15点的空间。如果有更多可用空间,Spacer 会扩展以填满剩余区域。
// Menu Button
Menu(content: {
Button {
size = "Small"
}label: {
Text("Small")
}
Button {
size = "Medium"
}label: {
Text("Medium")
}
Button {
size = "Large"
}label: {
Text("Large")
}
}) {
Label(title: {
Text(size)
.foregroundColor(.white)
}) {
Image(systemName: "slider.horizontal.3")
.foregroundColor(.white)
}
.padding(.vertical, 10)
.padding(.horizontal)
.background(.black)
.clipShape(Capsule())
}
}
.padding()
HStack(spacing: 0) {
ForEach(tabs, id: \.self) { tab in
Button {
currentTab = tab
}label: {
Text(tab)
.fontWeight(.bold)
.foregroundColor(currentTab == tab ? .black : .gray)
}
if tab != tabs.last {
Spacer(minLength: 0)
}
}
}
.padding()
ForEach(items.indices) { index in
// Card View
ZStack {
Color.black.cornerRadius(20)
Color.blue.cornerRadius(20)
.padding(.trailing, 65)
// Button
HStack {
Spacer()
Button {
}label: {
Image(systemName: "heart")
.font(.title)
.foregroundColor(.white)
.frame(width: 65)
}
Button {
addCart(index: index)
}label: {
Image(systemName: checkCart(index: index) ? "cart.badge.minus": "cart.badge.plus")
.font(.title)
.foregroundColor(.white)
.frame(width: 65)
}
}
CardView(item: items[index])
// drag gesture
.offset(x: items[index].offset)
.gesture(
DragGesture()
.updating($isDragging, body: { (value, state, _) in
// so we can validate for correct drag
state = true
onChanged(value: value, index: index)
})
.onEnded({ (value) in
onEnded(value: value, index: index)
})
)
}
.padding(.horizontal)
.padding(.top)
}
}
.padding(.bottom, 100)
}
}
}
// checking cart and adding item
func checkCart(index: Int) -> Bool {
return cart.contains { (item) -> Bool in
return item.id == items[index].id
}
}
func addCart(index: Int) {
if checkCart(index: index) {
cart.removeAll { (item) -> Bool in
return item.id == items[index].id
}
}
else {
cart.append(items[index])
}
// closing after added
withAnimation {
items[index].offset = 0
}
}
func onChanged(value: DragGesture.Value, index: Int) {
if value.translation.width < 0 && isDragging {
items[index].offset = value.translation.width
}
}
// onEnded is not working properlu
// may be its bug
// to avoid this we using update property on Drag Gesture
func onEnded(value: DragGesture.Value, index: Int) {
withAnimation {
// 65 + 65 = 130
if -value.translation.width >= 100 {
items[index].offset = -130
}
else {
items[index].offset = 0
}
}
}
}
var tabs = ["Tables","Chairs","Lamps","All"]
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
-
.gesture(DragGesture()...):为卡片添加拖拽手势。
DragGesture()
是用于检测拖动手势的类型。 -
.updating($isDragging, body: { ... }):使用
updating
方法可以更新一个状态变量(这里是$isDragging
)以指示当前是否正在拖动。body:
闭包中的代码会在拖动过程中被调用,这里设置state = true
表示正在拖动,同时调用onChanged(value:index)
函数进行处理。 -
.onEnded({ (value) in ... }):当拖动结束时,使用
onEnded
来处理最终的拖动结果。在闭包中调用onEnded(value:index)
函数来处理结束后的逻辑。
import SwiftUI
struct CardView: View {
var item: Item1
var body: some View {
HStack {
Image(item.image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: UIScreen.main.bounds.width / 3.2)
VStack(alignment: .leading, spacing: 10) {
Text(item.title)
.fontWeight(.heavy)
.foregroundColor(.black)
Text(item.subTitle)
.font(.caption)
.foregroundColor(.gray)
Text(item.price)
.fontWeight(.heavy)
.foregroundColor(.black)
}
Spacer(minLength: 0)
}
.padding()
.background(Color.white)
.cornerRadius(20)
.shadow(color: Color.black.opacity(0.08), radius: 5, x: 5, y: 5)
.shadow(color: Color.black.opacity(0.08), radius: 5, x: -5, y: -5)
}
}
import SwiftUI
struct TabButton: View {
var title: String
var image: String
@Binding var selected: String
var body: some View {
Button {
withAnimation(.spring()) {
selected = title
}
}label: {
HStack(spacing: 10) {
Image(systemName: image)
.resizable()
.renderingMode(.template)
.frame(width: 25, height: 25)
.foregroundColor(.white)
if selected == title {
Text(title)
.fontWeight(.bold)
.foregroundColor(.white)
}
}
.padding(.vertical, 10)
.padding(.horizontal)
.background(Color.white.opacity(selected == title ? 0.08 : 0))
.clipShape(Capsule())
}
}
}
在 SwiftUI 中,.renderingMode(.template)
是用于控制图像(如 SF Symbols 图标)渲染方式的修饰符。这个修饰符主要用于设置图像的填充模式,使其能够适应当前环境的颜色。.renderingMode()
: 这是一个视图修饰符,用于指定图像的渲染模式。.template
: 当你将渲染模式设置为 .template
时,图像将使用其所处环境的前景色(通常是文本颜色),而不是其原始颜色。
Menu的简单使用:
//在SwiftUI 中,Menu 是一个用于创建上下文菜单或弹出菜单的视图组件。它允许用户选择多个选项,而不必占用界面太多空间。
Menu("选择一项") {
Button("选项 1") {
print("选择了选项 1")
}
Button("选项 2") {
print("选择了选项 2")
}
Button("选项 3") {
print("选择了选项 3")
}
}
.padding()
.background(Color.blue.opacity(0.1))
.cornerRadius(10)
Menu {
Button {
}label: {
Label("Option 1", systemImage: "star")
}
Button{
}label: {
Label("Option 2", systemImage: "gear")
}
Button{
} label:{
Label("Option 3", systemImage: "circle")
}
} label: {
Label("Show Menu", systemImage: "ellipsis.circle")
}
Menu("美食") {
Button {
}label: {
Text("炸鸡")
}
Button {
}label: {
Text("烧烤")
}
Menu {
Button {
}label: {
Text("榴莲披萨")
}
Button {
}label: {
Text("奥尔良披萨")
}
} label: {
Text("披萨")
}
}