This article introduces several third-party open-source libraries used in the development of Health Notes.
SwiftUIX
SwiftUIX aims to fill the gaps of the still young SwiftUI framework, offering a wide array of components, extensions, and utility suites to complement the standard library. It’s the most comprehensive port of missing UIKit/AppKit features to date, striving to deliver in the most Apple-like manner possible. The project’s goal is to supplement the SwiftUI standard library, providing hundreds of extensions and views, enabling developers to effortlessly build applications through SwiftUI’s revolution.
This library provides many functionalities that Apple should but hasn’t provided. The project initiator is very young but has extensive experience in Mac development. It has maintained a high update frequency and maintenance status. It supports both UIKit and Appkit, which is friendly for users who need to develop across the entire Apple ecosystem. Due to ongoing issues with SwiftUI’s List and LazyVStack, the developer, who has also been troubled by these in his work, decided to remake the CocoaList feature recently, especially enhancing support for Fetchrequest.
Highly recommended for friends developing with SwiftUI.
The current issue is the lack of documentation. However, this can also be seen as a good thing for me. In the process of studying its usage, I got more opportunities to read and learn its code, gaining more understanding of SwiftUI, UIkit, etc.
Charts
Danielgindi’s Swift port of the famous Android chart library MPAndroidChart. It’s one of the few pure Swift solutions available and is also advantageous for supporting both UIKit and Appkit, with a lively demo community.
However, it seems the developer doesn’t plan to add too many features to the 3.x version. Many urgently needed features with existing solutions have not been accepted into the current version, so the overall visual presentation is quite traditional. There’s a lot of discussion about functionalities in the community, but few merges. The development of version 4.0 seems to have been going on for quite some time but isn’t progressing very ideally.
From an efficiency perspective, Charts is quite competent.
There are very detailed Chinese tutorials on Hangge, which greatly helped my learning.
For the needs of Health Notes development, I merged two mature community solutions into the current 3.6 version:
- Rounded Bar
dataSet.roundedCorners = [.topLeft,.topRight]
- Gradient Bar
dataSet.drawBarGradientEnabled = true
dataSet.colors = [UIColor(named: "barColor1")!, UIColor(named: "barColor1")!, UIColor(named: "barColor2")!]
dataSet.gradientPositions = [0, 40, 100]
Since the current version of Charts does not support responding to scroll stop events in charts, I added this feature myself.
// Called when scrolling stops
func chartScrollStop(_ chartView: ChartViewBase) {
print("stopped")
}
The modified code is available here.
Introspect
Introspect allows you to access the underlying UIKit or AppKit elements of a SwiftUI view. For example, with Introspect, you can access UITableView to modify separators, or access UINavigationController to customize the tab bar.
This is a highly recommended tool. Currently, the official control options provided in SwiftUI are limited, and if you want to do some in-depth customization, you usually write code to repackage UIkit controls. However, Introspect offers a clever way to make more adjustments to SwiftUI controls with a simple injection method.
For example:
Scroll only when content exceeds the display range
ScrollView {
....
}
.introspectScrollView { scrollView in
scrollView.isScrollEnabled = scrollView.contentSize.height > scrollView.frame.height
}
Show the clear button in TextField
TextField("note_noteName", text: $myState.noteName)
.introspectTextField { text in
text.clearButtonMode = .whileEditing
}
For new controls not yet specifically supported, you can easily inject them
Modifying the background color of TextEditor in SwiftUI 2.0
TextEditor(text: $text)
.introspect(selector: TargetViewSelector.sibling) { textView in
textView.backgroundColor = .clear
}
Such uses are very frequent in my entire development process.
SwiftDate
A time and date handling library written in Swift. Supports Apple platforms
as well as Linux.
It provides very comprehensive documentation, and there are also great Chinese tutorials on Hangge.
Since Health Notes needs to process a lot of data, especially merging and comparing data of the same time granularity, SwiftDate’s Region scheme offers a perfect solution.
In SwiftDate, I mostly use DateInRegion to handle dates. By setting
SwiftDate.defaultRegion = region
I almost don’t have to worry about localization issues of dates. It also provides some localization display schemes for dates and times (but not perfect).
Some examples of use:
Unless the user sets a specific time zone in the app, use the current device’s default settings:
if let data = UserDefaults.standard.data(forKey: "dateRegion"),
let region = try? JSONDecoder().decode(Region.self, from: data) {
SwiftDate.defaultRegion = region
}
else {
SwiftDate.defaultRegion = Region(calendar: Calendars.gregorian, zone: Zones.current, locale: Locales.current)
}
Determine the day difference between a date and a specified date (local time zone):
let startDate = DateInRegion(datas.first!.viewModel.date1).dateTruncated(at: [.hour,.minute,.second])!
duration = date.difference(in: .day, from: startDate) ?? 0
SwiftDate is a great choice when your program needs frequent date handling or has extensive localization needs!
SwiftUIOverlayContainer
SwiftUIOverlayContainer itself does not provide any preset view styles, but through it, you have full autonomy to implement the view effects you need. The main purpose of OverlayContainer is to help you complete basic work like animations, interactions, and style customization, allowing developers to focus their time and energy solely on the code of the view itself.
This is a library I wrote myself, and this time I used it to implement the side sliding menu on the screen.
Originally, its main use was not for this. Using it as a temporary solution for the side sliding menu is a stopgap measure, but it performs acceptably.
ZIPFoundation
ZIP Foundation is a library for creating, reading, and modifying ZIP archive files. It is written in Swift and based on Apple’s libcompression for high performance and energy efficiency.
Compact, efficient, and easy to use. Health Notes uses it to handle zip file operations during data import and export.
For example, unzipping backup data:
// Open sandbox read permission
_ = url.startAccessingSecurityScopedResource()
// Unzip
do {
try FileManager.default.unzipItem(at: url, to: URL(fileURLWithPath: NSTemporaryDirectory()))
}
catch {
}
MarkdownView
A Markdown file viewer based on WKwebView. Parsing of md is done by calling js libraries.
Since SwiftUI’s text layout capability is almost non-existent, I chose to save some text displays needed by the app, such as privacy policies, etc., in md format.
MarkdownView’s rendering efficiency is average, but my display needs are not big, so it’s not noticeable. However, its developer has scrambled the js files, so if you want to make more configurations to the markdown-it it calls, it’s almost impossible.
Additionally, by wrapping it in UIViewRepresentable, it’s impossible to get the correct frame size in SwiftUI, preventing proper display. I know very little about UIkit, so I only made the simplest modification to allow it to complete the needed functions in SwiftUI.
The modified version is available here.
Additionally, I added some simple modifications in the UIViewRepresentable wrapper, making it easy to replace images in md with local images in the Bundle.
The calling code is available for download here.
ExcelExport
Swift code for generating XLS files.
This code has been around for a while, but it was updated last year. However, I feel that the updated version is not as good as the previous one. The new version does not support exporting Date fields, and the Date field format exported by the old version also had issues in Excel. I merged the two versions and made the naming more SwiftUI-friendly.
You can download the modified code here.
To ensure that Excel correctly recognizes the date fields, the following processing must be done:
let date = DateInRegion(memo.viewModel.date).toFormat("yyyy-MM-dd")
let time = DateInRegion(memo.viewModel.date).toFormat("HH:mm:ss.FFF")
let dateCell = ExcelCell(date + "T" + time, type: .dateTime)
All the above libraries have been used in Health Notes 2.0.