macOS Menu Bar App (Code Along) | SwiftUI, Xcode
Summary
TLDR本视频教程向观众展示了如何创建一个Mac OS菜单栏应用程序,并与用户的剪贴板进行交互。视频由Flo主持,他首先回顾了之前在Twitter上发布的关于这个菜单栏应用程序的想法,并获得了积极的反响。接着,Flo逐步演示了如何使用Xcode创建项目,设置菜单栏图标,并实现点击菜单栏图标时弹出包含链接列表的弹出窗口。他还详细介绍了如何使用SwiftUI和Core Data来管理应用程序的数据,并展示了如何将链接保存到剪贴板以及如何退出应用程序。此外,Flo还分享了他在开发过程中的一些思考,包括对Swift UI预览功能的看法,以及如何手动生成类和属性。视频最后,Flo鼓励观众订阅频道,点赞视频,并在评论区分享他们的应用想法或其他教程建议。
Takeaways
- 🎓 学习如何创建一个macOS菜单栏应用,并了解如何与用户的剪贴板进行交互。
- 📱 通过点击菜单栏中的图标,可以弹出一个列表,用户可以从中选择链接并复制到剪贴板。
- 🛠️ 使用Xcode创建项目,并选择使用Core Data,随后根据需要对项目进行清理和配置。
- 📝 创建一个名为`ql link`的Core Data实体,包含id、title和url属性。
- 🔄 通过Swift UI创建用户界面,并使用`NSHostingController`来展示。
- 📂 利用状态栏控制器管理菜单栏图标,并定义点击事件来显示或隐藏弹出视图。
- 🔗 通过构建一个`NSPopover`和设置其行为为`transient`,来管理弹出视图的显示和隐藏。
- 💾 通过Core Data的`NSManagedObjectContext`来管理和获取链接数据。
- 🔍 使用Swift UI的`VStack`和`HStack`来布局视图中的链接列表和其他UI元素。
- 🔑 为链接列表中的每个链接项创建一个可点击的文本链接,并在旁边放置复制按钮。
- 🚫 移除主窗口,使应用仅作为一个菜单栏图标存在,通过设置`Application is agent`为`yes`实现。
- 📌 强调了应用的实用性,鼓励观众订阅频道、点赞视频,并在评论区留下反馈或其他应用创意。
Q & A
在视频中,Flo提到了一个用于macOS的菜单栏应用,这个应用的主要功能是什么?
-这个应用的主要功能是在macOS的菜单栏中显示一个图标,用户点击后可以查看和操作一系列链接。用户可以通过文本框输入链接的标题和URL,然后点击按钮将链接复制到剪贴板。此外,应用还包含退出按钮,允许用户退出程序。
Flo在视频中提到了哪些步骤来创建一个macOS菜单栏应用?
-Flo提到了以下步骤:1) 创建Xcode项目并初始化Core Data;2) 清除不需要的Core Data配置;3) 创建菜单栏应用的用户界面;4) 实现点击菜单栏图标后显示的弹出视图;5) 配置状态栏控制器以响应用户点击;6) 实现链接的保存和复制到剪贴板的功能;7) 优化应用界面和布局;8) 配置应用在启动时不显示主窗口,仅显示菜单栏图标。
在创建菜单栏应用的过程中,为什么Flo选择不使用Swift UI预览功能?
-Flo选择不使用Swift UI预览功能是因为在macOS上,Swift UI的实时预览功能并不像在iOS应用中那样工作。在macOS上,点击Swift UI预览的播放按钮会打开一个新的应用窗口来显示组件,而不是在Xcode内部实时显示,Flo认为这样的处理方式不如直接运行应用来得方便。
Flo在视频中提到了如何将链接复制到剪贴板,这个过程涉及到了哪些步骤?
-将链接复制到剪贴板的过程包括:1) 使用NSPasteboard的general实例;2) 调用clearContents方法清除剪贴板原有的内容;3) 使用setString方法将链接的URL作为字符串复制到剪贴板。
在macOS应用开发中,为什么有时候需要先清除剪贴板的内容,然后再复制新的内容?
-在macOS中,有时需要先清除剪贴板的内容,是因为NSPasteboard的setString方法或其他类似方法在没有先清除剪贴板的情况下可能不会生效。因此,为了确保新的内容能够被正确复制,需要先调用clearContents方法。
Flo在视频中提到了使用Core Data进行数据管理,那么在创建Core Data模型时,他创建了哪些属性?
-在创建Core Data模型时,Flo创建了一个名为'QLLink'的实体,它包含了三个属性:id(UID类型)、title(字符串类型)和url(字符串类型)。
在macOS的状态栏应用开发中,如何实现点击状态栏图标后显示一个弹出视图?
-在macOS的状态栏应用开发中,可以通过创建一个NSPopover实例,并在状态栏控制器中配置该实例,然后在用户点击状态栏图标时,使用show(relativeTo:of:preferredEdge:)方法来显示弹出视图。
Flo在视频中提到了如何隐藏应用的主窗口,只保留菜单栏图标,这是如何实现的?
-为了隐藏应用的主窗口,只保留菜单栏图标,Flo在Xcode的项目设置中,针对应用的target,打开了Info.plist文件,并添加了一个键为'Application is agent'的新值,将其设置为'YES'。这样,应用在启动时不会显示主窗口,只有菜单栏图标会显示。
在视频中,Flo创建了一个名为'PopOverView'的Swift UI视图,这个视图的作用是什么?
-在视频中,'PopOverView'是用来作为菜单栏应用点击后弹出视图的Swift UI视图。它包含了显示链接列表的界面,以及用于添加新链接的文本框和按钮。
Flo在实现复制链接到剪贴板的功能时,遇到了哪些问题,他是如何解决的?
-Flo在实现复制链接到剪贴板的功能时遇到了一个问题,即直接使用NSPasteboard的setString方法并不能将内容复制到剪贴板。他通过先调用clearContents清除剪贴板原有的内容,然后再使用setString方法复制新的链接,解决了这个问题。
在macOS菜单栏应用中,如何确保应用在用户关闭主窗口后仍然运行?
-在macOS菜单栏应用中,可以通过设置Info.plist中的'Application is agent'键为'YES',使得应用在用户关闭主窗口后仍然在后台运行,并且只保留菜单栏图标。
Flo在视频中创建了一个状态栏控制器,这个控制器的作用是什么?
-状态栏控制器的作用是管理菜单栏中的图标和与之相关的行为。在Flo的视频教程中,状态栏控制器负责创建和配置状态栏图标,以及定义点击图标后显示的弹出视图和相关的交互逻辑。
Outlines
📱 创建MacOS菜单栏应用
本段介绍了如何创建一个MacOS菜单栏应用,并与用户的剪贴板进行交互。Flo在昨天的直播后决定制作一个长视频,展示并解释他几天前编写并已在Twitter上发布的菜单栏应用。该应用允许用户点击菜单栏中的图标,通过文本框保存链接,并通过按钮将链接复制到剪贴板。Flo还提到了如何清理Xcode项目中的不必要组件,并创建了用于存储链接数据的Core Data模型。
🔗 构建和配置菜单栏项目
在构建成功后,Flo创建了包装属性以简化数据访问,并开始构建菜单栏项目。他创建了一个应用代理类来注册菜单栏项,并设置了一个弹出窗口,该窗口将在用户点击菜单栏项时显示。Flo还创建了一个状态栏控制器,用于管理菜单栏中的图标和弹出窗口的行为,包括显示和隐藏弹出窗口。
🛠️ 实现状态栏控制器
Flo创建了一个状态栏控制器类,用于管理状态栏图标和弹出窗口。他解释了如何初始化状态栏、状态栏项,并为其添加了一个按钮,该按钮在用户点击时会触发一个动作。Flo还展示了如何在用户点击按钮时显示或隐藏弹出窗口,并强调了在状态栏控制器中实现这一行为的重要性。
📑 配置应用代理和运行应用
Flo在应用代理中添加了一个状态栏控制器,并注册了应用代理,以便在应用启动时自动设置菜单栏项。他运行了应用并展示了菜单栏中的图标和弹出窗口。尽管弹出窗口的对齐和样式需要改进,但基本功能已经实现。Flo还提到了如何整理项目结构,以便于管理和查找相关代码文件。
🔄 创建和管理快速链接
Flo在弹出视图中创建了一个垂直堆栈,用于展示用户保存的快速链接。他使用了Core Data的托管对象上下文来获取链接数据,并使用Swift UI的列表来展示每个链接。Flo还展示了如何通过按钮将链接复制到剪贴板,并解释了为什么需要先清空剪贴板的内容。此外,他还提到了如何关闭弹出窗口,以便在用户点击复制按钮后提供更好的用户体验。
🖌️ 调整UI并添加新链接功能
Flo对UI进行了调整,为输入区域添加了内边距和固定宽度,以改善布局和外观。他创建了两个文本框,用于输入新链接的标题和URL,并添加了保存和退出按钮。Flo确保了在用户输入有效数据后,可以通过保存按钮将新链接添加到Core Data存储中。他还提到了如何清除文本框,以便用户连续添加多个链接,并展示了如何在不显示主窗口的情况下运行应用,使得应用仅以菜单栏项的形式存在。
🎬 完成视频和未来计划
在视频的最后,Flo总结了整个教程的内容,并鼓励观众订阅频道、点赞视频,并在评论区留下反馈或其他应用想法。他强调了这个菜单栏应用的实用性,并提出了可以添加的额外功能,如保存不同类型的数据。Flo希望观众能从这个轻松的教程格式中获得乐趣,并学习到有用的知识。
Mindmap
Keywords
💡macOS 菜单栏应用
💡粘贴板
💡Xcode
💡Core Data
💡SwiftUI
💡NSPersistentContainer
💡NSPopover
💡NSStatusBar
💡NSPasteboard
💡UUID
💡App Extension
Highlights
创建了一个Mac OS菜单栏应用程序,允许用户通过点击菜单栏图标来交互。
应用程序在菜单栏中显示一个SF图像图标,点击后不改变当前活动的应用程序。
提供了两个文本框供用户保存链接,并通过按钮将链接复制到剪贴板。
演示了如何通过Swift UI创建和管理应用程序的用户界面。
介绍了如何在Xcode中创建项目,并选择使用Core Data。
展示了如何清理和配置项目视图,以及如何移除不需要的Swift UI预览功能。
创建了一个名为'ql link'的Core Data实体,用于存储链接的ID、标题和URL。
手动生成类,而不是使用自动生成的代码,以提供更多的控制。
创建了一个状态栏控制器,用于管理菜单栏图标和弹出菜单的行为。
介绍了如何使用NSPopover和NSViewController来实现菜单栏的弹出功能。
展示了如何在应用程序代理中注册菜单栏项,并在应用启动时设置弹出内容。
通过实现一个按钮动作来控制弹出菜单的显示和隐藏。
创建了一个Swift UI视图,用于显示和管理快速链接,并使用Core Data进行数据存储。
介绍了如何使用NSPasteboard将字符串复制到剪贴板,并处理相关的API细节。
提供了一个示例,展示了如何在用户点击保存按钮时将新链接添加到Core Data存储中。
展示了如何通过设置应用程序为代理来隐藏主窗口,使应用程序仅在菜单栏中运行。
讨论了应用程序的潜在扩展性,包括添加更多特性和保存不同类型的数据。
鼓励观众订阅频道、点赞视频,并在评论区留下反馈或其他应用程序的创意。
Transcripts
in this video you will learn how to create a mac os menu bar app
and how to interact with the user's paste
board hey this is Flo and after yesterday's successful first stream at least yesterday
as of the date of this recording i figured i might as well do another koda long style video
and this time i'm doing or i'm working on a menu bar app for mac os
that i've already written actually a few days ago and i've posted about it
on twitter so if you don't follow me on twitter yet go ahead and do that
and people on twitter seem to like the idea so i figured i would just do another color long
video recreating the app and explaining my thought process explaining how i work and how this app can
be made so you've already seen how it works there will be a sf image in your menu bar and when you
click on it you will notice that the active app does not change to whatever our app is called
it stays as xcode in our case then there will be a list of links which we can save through these
two text fields and then if we hit one of these buttons the link will be copied to the clipboard
of course we can also quit the app with the quit button i'll demonstrate that later in
the app that we will actually build okay so to get started i already created an xcode project and i
selected use core data because of that there is always a bunch of stuff that we need to
clean up first so let me get rid of most of those things so in our view body let's say welcome to
menu bar links that's what i call the project and then let's give that a ton of padding
let's remove the add item function let's remove the delete items function let's remove this item
formatter and let's also just remove that preview because we will not be using swift ui previews in
this project i don't like using them on the mac because the live preview feature actually doesn't
really work on a mac as in it's not running inside of xcode as it is for an ios app
but when you click the little play button in your joy preview it will actually uh open a new window
of your app and display that component there i don't like how that's handled so i might as
well just run the app you know what i mean so i just get rid of the switch ui preview on the mac
let's also clean up the persistence controller i will not be using the preview controller
so that can go i will also remove all of this in-memory stuff and also remove this large
arrow command and then we will only have our ns persistent container we will load the persistent
stores and we will make sure that automatically merges changes from parent is set to true
i don't think that this is really important as we're not dealing with cloud kit i think this
line is only important for cloud kit but we'll leave it in anyways then let's also clean up the
model so we don't need this random item entity so let's get rid of that and i think we can just get
started by creating our model so let's add entity i will call this one ql link for quick links link
and it will have an id
a title and a url the url will be a string the id will be a uid and the title will also be a string
if you have watched my previous live stream where i've built a pros and cons mac
app then you will know that i tend to manually generate my classes so if i select the entity
and then here in the inspector for the code gen i just select manual slash none
hide this again and then go to editor create ns manage object subclass hit next
let's create a new photo for that actually
and let's save it into this data folder that i just created
okay for some reason the folder didn't work
so let's just create a group let's call it data
interesting so let's call it call data and then move both of these in there
now let's hit command b to build the project and see if it works
okay build succeeded these are just two xcode arrows the first time that you build a core
data project this will pretty much always happen so let's just press command shift k
okay and then in here let's create some wrapper attributes so we don't always have to unwrap the
properties so let's create a var wrapped id which will be of type uid in this case we will just
force unwrap our id so we have we'll have to make sure that every time that we create a new qr link
we provide a valid uid then let's also create a wrapped title which will be a string and that's
just our title or an empty string if there is none and then also a wrapped url which will be a url
and in here we will just construct a new url via a string of our url
or actually
url and we'll force unwrap both of these
because in this app we will make sure that every time that the user creates a new qr link
that they set a id or that we set an id that they set a title and a url so force unwrapping here
should not be an issue because we make sure that every time that one of these instances get created
there will be a title and a url so in fact we can just get rid of this new core listing operator
here as well and just force unwrap the title as i said might not want to do this in production
but i think for an app where we really strictly control the input it is fine to do it like this
okay so the call data part is actually already done next up let's create a new
group here and let's call it menu bar and this will contain all of the code that we need to
add a menu bar item so first of all we need to create an app delegate
that is needed to register the menu bar item so let's import swift ui and let's create a class
called app delegate which will inherit from ns object and conform to ns application delegate
this class will need a pop over that that is basically
what's shown when the user clicks on the menu bar item so this thing here is called
an ns pop over and this will be an ns pop over and now this is a bit ugly
but i will make this object static because we will need to access it in some other places
so yeah i'll make it static but maybe you shouldn't do that i'm not too sure i'm just
gonna go ahead and do it and leave you with the information that it's probably not the best idea
okay and next let's application did finish launching is the delegate function that we
need here and here we can set our self dot pop over we need that capital s self because
the pop over is a static variable to access the static variable we need to access it via
the class we could also say appdelegate.popover i like to say self.popover so it's instantly
recognizable that this is actually in the same class it's just a static variable
and then here we can set the content viewcontroller to be an ns hosting controller
with a root view and now we don't have that view yet so let's create that
so let's create a new file switch your eye view and i'll just call it pop overview
we can leave that as is for now and then in our app delegate here we can say
the root view is a pop overview but as we're working with call data
we will have to pass the manage object context into the search ui environment so to do that
we will say dot environment access dot managed object context and the context will be our shared
persistence controllers context so we will say persistencecontroller.shared.container.viewcontext
okay to make sure that the pop over gets hidden again when the user clicks somewhere
else on their device we will have to set the behavior of the pop over to be transient
okay next up let's create a status bar controller that's what i called it
and we will use that to fill in this sf symbol here and to tell it what to do once the user
clicks on it so let's create a new file and let's call it status bar controller
okay so let's import app kit let's create a class called status bar controller this will have a
private var status bar which is an ns status bar so status bar of type n as status bar
and then two more attributes and and a status item
and then ns popover which will then present our circular view so let's add
a status item as well and a status item and then let's also add our pop over
just like that okay let's create an initializer where we pass in a popover which we then
configure in the status bar controller so this will be of type ns pop over first thing
that we do is make sure that we save it into our property here so self.popover equals that popover
we will also initialize the status bar so status bar equals dot it and then status item is our
status bar and then we can create a new status item from that and a status bar with a length of
ns status item dot variable length you can also specify how large your status item will be
but i think it's just a bit easier to work with it if you just select any status item.variable length
i think that's the easiest solution and then next let's configure the button give it an action
give it a target and give it an ns image to show in the menu bar
so let's grab the button first of all so let's say if let button equals our status item
dot button this is a optional property so we have to do all this if that stuff and then in here we
can configure so we can say button.image is an ns image with a system symbol name
and you can use any system symbol that you want i will just use house right now the one
that i've showed you earlier is list dot bullet dot rectangle dot fill but you can use any as
of symbol that you'd like and as this is just an example project let's set the accessibility
description to nil if you were to create an app like this and then push it to the app store you
should probably care about accessibility and add a description right there next let's add an action
and that is a selector and we'll have to create a function for that so let's create an add
objective c func show our app that's what we want to happen when the user clicks on um the ns image
so it will have a sender of any object that's just the signature that we need
okay
and now we can use that here in our selector and let's also make sure that the
target is set to self so this selector is called on our own instance next let's implement this
show app function so there will be two cases either the pop over is shown then we want to
hide our switcher eye view and else we want to show us with your view so hiding
is actually super easy let's just say popover dot perform close with no sender we don't care
about that just close the pop over and else if we want to show it we can just say popover dot
show relative to the bounds of our status item button
so let's say status item dot button we can false unwrap this because we have created a button here
dot bound
of our status item dot button once again the preferred edge is the maximum y edge so
the top basically okay and that's already everything in our status bar controller
let's go back into our app delegate and in here we now need to create a status bar controller
so let's add a variable for that let's call it status bar and that will be of type status bar
controller optional and then we can say status bar is a new status bar controller with our pop over
self.pop over of course all right so now all of the menu bar stuff
is almost set up the last thing that we need to do is register this app delegate in our app
so to do that let's open our menu by links app let's go in here and let's say add ns application
delegate adapter with the type of appdelegator itself is our new app delegate this way it's
registered in the app and the system will actually call all of these application did
finish launching functions and so on okay we can close the app delegate we can close the app
and i think now we can give it a run and perhaps already see something in the menu bar
okay so now the app is running we have our window with the welcome to menu bar links content view
and then we also have this little house icon here in the menu bar
and if we click that then a pop over will be shown it's not well aligned and it looks very
bad because there is no padding but we will fix all of that okay so let's close the app again
let's also clean up the sidebar here a bit so let's move the core data model and the
persistence controller into the core data group let's collapse both of these let's move the pop
overview up a bit and i think that's already the next thing that we can have a look at so
let's open so let's open the pop overview next
and in here we now create basically everything that's in this app here
so for that first of all since we're dealing with core data we need a managed object context
and then we can also create a fetch request for our ql links so let's create an add fetch request
with empty sort descriptors we don't really care about sorting them if you care about sorting them
this is the place where you should do it and then let's call this variable links and this will be a
fetched results of ql link that's what we call our core data class quick links link basically
and then inside of the view let's create a vstack
with an alignment of leading
we don't care about the spacing for now in here let's iterate over all of these links
with the wrapped id as our identifier
and let's grab a link in here for each link let me remind you we basically have an h stack with a
clickable text link and then a spacer and a button on the right hand side which copies the link
to the paste board so let's get started by creating an age stack first element will be a link
with a title of our wrap title and a destination of our wrapped url
then we said we want to have a spacer
and next there will be a button
with a label that is an sf symbol so system name and this one has a bit of a longer name
the one that i used so let's use the same one again it's called arrow right on right
doc on clipboard i think that's the correct name next up let's do that and it's pastebot management
so you'd think that it's super easy and i will show you how the basic api to copy something
into the pasteboard works so you can just say ns pasteboard dot general dot set string or set any
other type that you want we will use the set string we will set the link dot wrapped url
and as the type we will of course use string because we are copying a string
and actually we're not using the wrapped url we're using the
your l and then force unwrap it because we want a string and not a url object
don't mind this xcode internal error i don't know why but ever since xcode 13.3 came around
it constantly crashes for me now as i said you might expect this to be super easy but only
using this line of code and setting a string will actually do nothing to the end spaceboard
you have to clear its contents first to do that let's say ns pasteboard.general.clearcontents
and now the set string function actually does something i have no idea why this api is in
place i think it would be a lot easier to use if you don't have to call clear contents first
but that's just the way it is and then we also want to
close the pop over again so let me demonstrate that in the completed app
when i click the button the pop over closes we will also want to have that behavior
and to achieve that we can call our appdelegate dot pop over and this is why we made it a static
property so we can access it right here and we can then just call perform close with no sender
okay so that's basically the top portion done and let's do the bottom half so as you can see
there is a divider and then two text fields and two buttons so let's collapse this for each so
we have a bit more space let's create a divider for the divider let's also give it some vertical
padding of maybe four points and below that let's create a new v-stack so everything is yeah in its
own component basically you could extract that to a different view i'll just keep it in a stake here
it's not really needed because you already have a v stack surrounding it i just like to separate
my components a bit indicates that i want to pull it out into its own swift ui view later on
so in this vstack as we already discussed there will be two text fields
the first one will be the title of our new link and the second one will then be the url
so let's create two new state properties the first one will be link title that's a string and
of course it will be empty by default let's just create a second one called link url
and let's bind to these so first one is link title the second one is link url
and next we will add the quit button and the save button for that let's create an h stack
first button will just say quit and this one will call terminate on the ns application so ns
application dot shared o ns application dot shared dot terminate with no sender again
then a spacer in between and a second button called save
now i want this button to be highlighted so the user knows that this is the primary button so we
will just add a bolded prominent button style this will then also give it a tint color that
the user selected in their mac os settings okay and in here let's make sure that both of the text
fields are filled out correctly so let's say so let's make sure that there's a valid url so if url
with the string of our link url is not new and the link title is not empty
is not empty and the link url also is not empty i'm not sure if an empty url is actually valid so
i'll just double check it here make sure that is a valid url and then the string is also not empty
if all of that is the case then we can create a new ql link
that will be a qr link with our current view context for that qr link we will
set the id to be a brand new uuid we will set the title to be our link title
and we will set the url to be our link url
then let's save the changes so try view context and save and let's also clear out both of the
text fields in case you want to add multiple links at once and of course there is a typo here
okay so let's say link title is an empty string and link url is also an empty string
okay just a few more things so let's run this right now see how it looks and then
see what we want to change okay so still the main app window will open
with our content view we have our menu bar item and that's what it looks like right now so
of course we don't have any links yet but we have a text field another text field and our
two buttons but they're really crammed in there so let's give it some padding and a frame as well
so on our v stack closing brackets let's add some padding and let's give it a fixed width of 200
okay let's run that again
and now it already looks a lot better of course there are still no links because
we haven't entered any so let's enter a link and for that i will actually
use the completed app so i will just copy my twitter url
let's call this one twitter and as url let me paste what i just copied there you can see that
it definitely works when i hit save then it will be entered here okay so one more thing
you might want to remove the button style for this button so let's do that first expand our for each
again and then for the second button let's add a button style of plane that should get rid of it
okay there's basically one last thing and if i run the app again i can show you
why it's needed or why it might be nice so our app really only lives in a menu bar the
main window serves no purpose at all everything happens in this little menu bar pop over so why
don't we just get rid of this window altogether to do that let's go into the application project
select the target go to info.pdist and add a new value and scroll down
until you can see application is agent and then you can just set that to yes
now if we hit save and run the app again
the window will open because we had it open last time but if we close it now
and run the app again then it will not open again so what this means is the first time that the user
opened opens the app for example you could show a little onboarding window and then the next
times that the app will be open no window will be shown and you will just have your menu bar item
okay that's it with the video i hope you learned something i hope you found it enjoyable
i think this app is rather useful you could of course add more features
to it and also save different kinds of data this is just what i needed a few days ago so i built it
if you enjoyed the video please make sure to subscribe to the channel
like the video and leave a comment down below with other app ideas that we should build in
this more relaxed color long format also of course tutorial ideas if you have any
you
Weitere verwandte Videos ansehen
![](https://i.ytimg.com/vi/KamCx-Hfdxk/hq720.jpg)
User Experience and Animations in SwiftUI app | Todo List #5
![](https://i.ytimg.com/vi/EPdivac0kwE/hq720.jpg)
Create a List of Todo items in SwiftUI | Todo List #1
![](https://i.ytimg.com/vi/3CasiUiJPVo/hq720.jpg)
Adding an App Icon and Launch Screen to SwiftUI | Todo List #7
![](https://i.ytimg.com/vi/nwpmWu1SP1k/hq720.jpg)
Add a ViewModel with @EnvironmentObject in SwiftUI | Todo List #3
![](https://i.ytimg.com/vi/UeG9RAVE8sE/hq720.jpg)
Unreal Engine 5 RPG Tutorial Series - #20: AI Behavior Trees Patrolling
![](https://i.ytimg.com/vi/ljRXA0Eg4kE/hq720.jpg)
New apk without Activation for play games with keyboard and mouse in mobile like Computer |free fire
5.0 / 5 (0 votes)