SwiftUI小功能模块系列
0001、SwiftUI自定义Tabbar动画效果
0002、SwiftUI自定义3D动画导航抽屉效果
0003、SwiftUI搭建瀑布流-交错网格-效果
0004、SwiftUI-<探探App>喜欢手势卡片

技术:SwiftUI3.0、喜欢卡片、手势、探探App、TinderApp
运行环境:
SwiftUI3.0 + Xcode13.4.1 + MacOS12.5 + iPhone Simulator iPhone 13 Pro Max

SwiftUI搭建<探探App>喜欢手势卡片-效果

  • 概述
  • 详细
    • 一、运行效果
    • 二、项目结构图
    • 三、程序实现 - 过程
      • 1.创建一个项目命名为 TantanUI
      • 1.1.引入资源文件和颜色
      • 2. 创建一个虚拟文件`New Group` 命名为 `View`
      • 2. 创建一个文件`New File` 选择`SwiftUI View`类型 命名为`Home`
      • 2. 创建一个文件`New File` 选择`SwiftUI View`类型 命名为`StackCardView`
      • 3. 创建一个虚拟文件`New Group` 命名为 `Model`
      • 3. 创建一个文件`New File` 选择`SwiftUI View`类型 命名为`User` 、并且删除预览视图、改造成模型 继承`Identifiable`
      • 4. 创建一个虚拟文件`New Group` 命名为 `ViewModel`
      • 4. 创建一个文件`New File` 选择`SwiftUI View`类型 命名为`HomeViewModel` 、并且删除预览视图、改造成模型 继承`ObservableObject` 类型是`class`
    • Code
      • ContentView - 主窗口
      • Home - 主页
      • StackCardView.swift - 卡片视图
      • User - 模型
      • HomeViewModel - 视图模型
    • demo源码

概述

使用SwiftUI做一个类似探探App的喜欢手势卡片

详细

一、运行效果

二、项目结构图

三、程序实现 - 过程

思路:
1.创建主窗口
2.搭建导航和底部按钮和中间卡片部分
3.添加卡片用户数据、自定义喜欢卡片UI
4.处理拖拽手势操作、左右滑动进行通知卡片页面删除卡片

1.创建一个项目命名为 TantanUI


1.1.引入资源文件和颜色

颜色
Blue #8BBDE6
Gray #9A9D9F
Pink #E76397
Yellow #E7BB71
随机美女6-10张

2. 创建一个虚拟文件New Group 命名为 View


2. 创建一个文件New File 选择SwiftUI View类型 命名为Home



2. 创建一个文件New File 选择SwiftUI View类型 命名为StackCardView




3. 创建一个虚拟文件New Group 命名为 Model


3. 创建一个文件New File 选择SwiftUI View类型 命名为User 、并且删除预览视图、改造成模型 继承Identifiable



4. 创建一个虚拟文件New Group 命名为 ViewModel


4. 创建一个文件New File 选择SwiftUI View类型 命名为HomeViewModel 、并且删除预览视图、改造成模型 继承ObservableObject 类型是class


Code

ContentView - 主窗口

主要是展示主窗口Home

//
//  ContentView.swift
//  Shared
//
//  Created by 李宇鸿 on 2022/8/13.
//import SwiftUIstruct ContentView: View {var body: some View {Home()}
}struct ContentView_Previews: PreviewProvider {static var previews: some View {ContentView()}
}

Home - 主页

思路

  1. 创建导航
  2. 创建底部四个按钮
  3. 创建卡片模块
  4. 创建卡片数据、创建卡片UI
  5. 监听卡片没有情况 按钮不可点击
  6. 监听按钮和手势的操作卡片的通知传递
//
//  Home.swift
//  TanTanUI (iOS)
//
//  Created by 李宇鸿 on 2022/8/14.
//import SwiftUIstruct Home: View {@StateObject var homeData : HomeViewModel = HomeViewModel()var body: some View {VStack{Button{}label: {Image("menu").resizable().renderingMode(.template).aspectRatio(contentMode: .fit).frame(width: 22, height: 22)}.frame(maxWidth:.infinity,alignment: .leading).overlay(Text("Disover").font(.title.bold())).foregroundColor(.black).padding()// 用户布局ZStack{if let users = homeData.displaying_users{if users.isEmpty{Text("Come back later can find more matches for you!").font(.caption).foregroundColor(.gray)}else{// 显示卡片……//从Zstack开始反转牌//你可以在这里使用反向操作…//或者你可以在抓取用户时…ForEach(users.reversed()){ user in// 卡片视图StackCardView(user: user).environmentObject(homeData)}}}else{ProgressView()}}.padding(.top,30).padding().padding(.vertical).frame(maxWidth:.infinity,maxHeight: .infinity)// 多个按钮HStack(spacing:15){Button{}label: {Image(systemName: "arrow.uturn.backward").font(.system(size: 15,weight: .bold)).foregroundColor(.white).shadow(radius: 5).padding(13).background(Color("Gray")).clipShape(Circle())}Button{doSwipe()}label: {Image(systemName: "xmark").font(.system(size: 20,weight: .black)).foregroundColor(.white).shadow(radius: 5).padding(13).background(Color("Blue")).clipShape(Circle())}Button{}label: {Image(systemName: "star.fill").font(.system(size: 15,weight: .bold)).foregroundColor(.white).shadow(radius: 5).padding(13).background(Color.yellow).clipShape(Circle())}Button{doSwipe(rightSwipe: true)}label: {Image(systemName: "suit.heart.fill").font(.system(size: 20,weight: .black)).foregroundColor(.white).shadow(radius: 5).padding(13).background(Color("Pink")).clipShape(Circle())}}.padding(.bottom)// 设置按钮不可点击.disabled(homeData.displaying_users?.isEmpty ?? false).opacity((homeData.displaying_users?.isEmpty ?? false ? 0.6 : 1))}.frame(maxWidth:.infinity,maxHeight: .infinity,alignment: .top)}// removing cards when doing Swipe...// 在刷牌时移除卡片…func doSwipe(rightSwipe: Bool = false){guard let first = homeData.displaying_users?.first else{return}// Using Notification to post and receiving in Stack Cards...// 使用通知在堆叠卡片中寄收……NotificationCenter.default.post(name: NSNotification.Name("ACTIONROMBUTTON"), object: nil,userInfo: ["id": first.id,"rightSwipe": rightSwipe])}}struct Home_Previews: PreviewProvider {static var previews: some View {Home()}
}

StackCardView.swift - 卡片视图

主要是做 卡片UI展示
思路

  1. 搭建卡片UI
  2. 监听上层传递的通知手势处理拖拽操作 进行监听是否删除卡片
  3. 拖拽卡片动画设计

//
//  StackCardView.swift
//  TanTanUI (iOS)
//
//  Created by 李宇鸿 on 2022/8/15.
//import SwiftUIstruct StackCardView: View {@EnvironmentObject var homeData: HomeViewModelvar user: User// 手势属性……@State var offset : CGFloat = 0;@GestureState var isDragging : Bool = false@State var endSwipe : Bool = falsevar body: some View {GeometryReader {proxy inlet size = proxy.sizelet index = CGFloat(homeData.getIndex(user: user))// 显示下两个卡在顶部像一个堆栈....let topOffset = (index <= 2 ? index : 2 ) * 15ZStack{Image(user.profilePic).resizable().aspectRatio(contentMode: .fill)// 减少宽度.frame(width: size.width - topOffset, height: size.height).cornerRadius(15).offset(y:-topOffset)}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)}.offset(x:offset).rotationEffect(.init(degrees: getRotation(angle: 8))).contentShape(Rectangle().trim(from: 0, to: endSwipe ? 0 : 1)).gesture(DragGesture().updating($isDragging, body: { value, out, _ inout = true}).onChanged({ value inlet translation = value.translation.widthoffset = (isDragging ? translation : .zero)}).onEnded({ vlaue inlet width = getRect().widthlet translation = vlaue.translation.widthlet checkingStatus = (translation > 0 ? translation : -translation)withAnimation {if checkingStatus > (width / 2){// 删除卡片offset = (translation > 0 ? width : -width) * 2endSwipeActions()if translation > 0 {rightSwipe()}else {leftSwipe()}}else{// reset...// 重置offset = .zero}}}))// 接收通知发布.....onReceive(NotificationCenter.default.publisher(for: Notification.Name("ACTIONROMBUTTON"),object:nil)) { data inguard let info = data.userInfo else{return}let id = info["id"] as? String ?? ""let rightSwipe = info["rightSwipe"] as? Bool ?? falselet width = getRect().width - 50if user.id == id {// 删除卡片withAnimation{offset = (rightSwipe ? width : -width) * 2endSwipeActions()if rightSwipe {self.rightSwipe()}else {leftSwipe()}}}}}// 旋转func getRotation(angle: Double)-> Double{let rotation = (offset / (getRect().width - 50)) * anglereturn rotation}func endSwipeActions(){withAnimation(.none) {endSwipe = true}//移走卡后,将卡从数组中移除以保存内存…//根据你的动画持续时间延迟时间…DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {if let _ =  homeData.displaying_users?.first{let _ = withAnimation {homeData.displaying_users?.removeFirst()}}}}func leftSwipe() {//  在这里做动作print("Left Swiped")}func rightSwipe() {//  在这里做动作print("right Swiped")}
}struct StackCardView_Previews: PreviewProvider {static var previews: some View {ContentView()}
}// 扩展视图获得边界…
extension View{func getRect()->CGRect{return UIScreen.main.bounds}
}

User - 模型

用户模型

import SwiftUI// 用户模型
struct User: Identifiable {var id = UUID().uuidStringvar name : Stringvar place : Stringvar profilePic : String
}

HomeViewModel - 视图模型

视图模型

  1. 处理创建用户数据
  2. 是否还有用户数据展示
  3. 获取当前图片的索引
import SwiftUI// 视图模型,它保存所有用户数据…
class HomeViewModel: ObservableObject {//存储所有获取的用户在这里…//因为我们正在构建UI,所以在这里使用示例用户…@Published var feched_users : [User] = []@Published var displaying_users : [User]?init(){// 获取用户……feched_users = [User(name: "Natalia", place: "Vadlia NYC", profilePic: "User1"),User(name: "Elisa", place: "Central NYC", profilePic: "User2"),User(name: "Jasmine", place: "Metropolitan Museum NYC", profilePic: "User3"),User(name: "Zahra", place: "Liberty NYC", profilePic: "User4"),User(name: "Angelina", place: "Empier State NYC", profilePic: "User5"),User(name: "Brittany", place: "Time Squart NYC", profilePic: "User6")]//存储在显示用户…//显示用户的是什么?//它将根据用户交互来更新/删除,以减少内存使用…//同时我们需要所有获取的用户数据…displaying_users = feched_users}// 检索索引…func getIndex(user: User)->Int{let index = displaying_users?.firstIndex(where: { currentUser inreturn user.id == currentUser.id}) ?? 0return index}}

demo源码

如需看源码,请点击下载!

【SwiftUI模块】0004、SwiftUI-<探探App>喜欢手势卡片相关推荐

  1. 【SwiftUI模块】0008、SwiftUI-自定义启动闪屏动画-App启动闪屏曲线路径动画

    SwiftUI小功能模块系列 0001.SwiftUI自定义Tabbar动画效果 0002.SwiftUI自定义3D动画导航抽屉效果 0003.SwiftUI搭建瀑布流-交错网格-效果 0004.Sw ...

  2. 【SwiftUI模块】0007、SwiftUI新手指引-新手指示-聚光灯介绍说明

    SwiftUI小功能模块系列 0001.SwiftUI自定义Tabbar动画效果 0002.SwiftUI自定义3D动画导航抽屉效果 0003.SwiftUI搭建瀑布流-交错网格-效果 0004.Sw ...

  3. 【10】AccessibilityService实现探探app的自动化喜欢和不喜欢+ [as 3.0如何打开层级调用uiautomatorviewer]

    目前版本3.1.8  仅供学习使用!!!!!切勿用作非法用途,否则后果自负! 直接写这个东西 可能是有些唐突 因为你们可能不知道这是一个什么玩意 如果你想看过于这个Accessibility服务的一些 ...

  4. iOS APP开发项目案例(仿探探优化)--FaceFriend

    源码请到Github上下载Github源码. ios开发的基本知识:OC语言基础.Foundation基础框架.各个控件的UI界面编程(UITableView.UINavigationControll ...

  5. 继安卓市场下架后 探探App也在苹果商店下架

    [TechWeb]此前,陌生社交App探探遭遇各大安卓应用市场下架处理,原因是传播淫秽色情等违规违法信息. 目前,探探在苹果商店也遭到下架处理,苹果用户也搜索不到该App. 下架处理后,探探方面曾回应 ...

  6. linux上的社交软件下载,探探交友app免费版-探探交友真实app下载v4.2.9.2-Linux公社...

    探探交友app是一款非常好用的社交聊天平台,使用方法非常简单,喜欢的话可以将名片向右滑,不喜欢的话就向左滑,只有相互喜欢的两人才可以开始聊天,避免了很多陌生人的消息,减少骚扰,探探交友app免费版非常 ...

  7. 你不知道的“探探”引流套路,让更多人“喜欢你”!

    社交软件APP特别多,除了熟人之间的社交app,我想大家更容易喜欢陌生人的交友软件,你们懂的! 显而易见,探探是一款具有陌生人聊天的软件,且它的用户量也已经过亿,探探一般都会根据你的个人资料.兴趣爱好 ...

  8. 社交通讯产品-app榜单第三:探探

    ​ 一.产品介绍 1. 产品名称:探探 2. 产品版本:2.4.1 3. 体验平台:iPhone 6s 4. 体验系统:IOS 9.3.5 5. 产品定位: 探探是一种全新的相遇方式.以双向的&quo ...

  9. 【SwiftUI模块】0052、使用SwiftUI设计时尚旅行应用程序UI

    SwiftUI模块系列 - 已更新52篇 SwiftUI项目 - 已更新5个项目 往期Demo源码下载 技术:SwiftUI.SwiftUI4.0.旅行.旅行App.旅行应用程序.时尚旅行 运行环境: ...

最新文章

  1. 《GTA 5》走进现实!AI逼真还原游戏街景,还能“脑补”细节 | 英特尔出品
  2. asp.net数据绑定之Eval和Bind区别
  3. 解决IDEA快捷键 Alt+Insert 失效的问题
  4. .net DataGrid绑定列手动添加数据
  5. Python的单引号、双引号和三引号的字符串
  6. systemd常见使用总结
  7. 构建高可用服务器之 Keepalive参数详解
  8. 深度学习(八)——fine-tuning, 李飞飞
  9. mysql与串口通信_虚拟机串口与主机串口通信·小程序(下)
  10. app inventor HTML5,[App Inventor] Web客戶端元件 POST 傳值的使用方式
  11. XEngine:深度学习模型推理优化
  12. 生产者消费者 java实现_Java生产者消费者的三种实现
  13. Android 使用 sendevent 模拟鼠标和键盘事件
  14. Eclipse — 导包异常总结《I》
  15. MySQL数据库数据存放位置修改
  16. 个人发卡网-轻量版-可自定义接口
  17. element-ui中table 去掉表头、去掉边框线、去掉鼠标悬停背景颜色
  18. Outlook设置规则的一点提示
  19. 丁火生于未月命理分析_丁火生于未月的性格特征
  20. win7 提示 由于无法验证发布者,windows阻止控件安装 解决办法

热门文章

  1. 哈罗出行数据挖掘实习生电面题 (一面二面)
  2. Java中的基本类型与封装类型以及自动装箱、拆箱
  3. 初识Python,画太阳黑子图
  4. 22、综合布线工程常用设备材料介绍及施工注意事项
  5. 无线网和网吧服务器,无线宽带在网吧接入中的应用详解
  6. js判断是否安装pdf播放器
  7. 防WiFi万能钥匙蹭网,一招就够了
  8. 1.1 面对ChatGPT应有的态度:君子生非异也,善假于物也!
  9. MAC 安装VMware后发现黑屏
  10. iPad能不能装c语言的编译器,IPhone/IPad/IPod安装GCC的方法