如何解决SwiftUI 不使用自动布局,如何为所有设备创建唯一大小的界面?
我之前不使用 SwiftUI 并尝试创建媒体小部件,但我无法从另一个程序(YouTube 音乐媒体小部件)重新创建此小部件的副本,我在不同屏幕上的第四个单元格具有不同的边距,我不知道如何修复这个边距,因为 SwiftUI 没有自动布局。我在下面发布了我的小部件的代码,如果有人知道我做错了什么,请纠正我。
我的小部件代码:
import WidgetKit
import SwiftUI
import Intents
import Foundation
struct Provider: IntentTimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {...}
func getSnapshot(for configuration: ConfigurationIntent,in context: Context,completion: @escaping (SimpleEntry) -> ()) {...}
func getTimeline(for configuration: ConfigurationIntent,completion: @escaping (Timeline<Entry>) -> ()) {...}
}
struct SimpleEntry: TimelineEntry {...}
struct WidgetTestEntryView : View {
var entry: Provider.Entry
var deeplinkURLFirst: URL {
URL(string: "\(WIDGET_DEEP_LINK)0")!
}
let iconSize: CGFloat = 75.0
var widgetLabel = "Favourites"
let mainColor = Color(red: 0.218,green: 0.215,blue: 0.25)
var body: some View {
vstack(spacing: 0) {
GeometryReader { geo in
HStack(spacing: geo.size.width * 0.4){
Text(widgetLabel).foregroundColor(.white).font(.system(size: geo.size.width * 0.045,weight: .semibold,design: .default)).offset(y: 2)
Image("Label2").resizable().frame(width: geo.size.width * 0.15,height: 15,alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
}.frame(maxWidth: .infinity,maxHeight: geo.size.height * 0.7).background(Color.black).offset(y: -5)
}
GeometryReader { geo in
HStack(spacing: geo.size.width * 0.1 / 7) {
Link(destination: deeplinkURLFirst) {
ZStack {
RoundedRectangle(cornerRadius: 10).foregroundColor(mainColor).frame(width: iconSize,height: iconSize)
Image(base64String:"")?.resizable().frame(width: iconSize,height: iconSize)
.cornerRadius(10)
.background(mainColor).cornerRadius(10)
}.frame(width: iconSize,height: iconSize)
}
Link(destination: deeplinkURLFirst) {
ZStack {
RoundedRectangle(cornerRadius: 10).foregroundColor(mainColor).frame(width: iconSize,height: iconSize)
Image(base64String: "")?.resizable().frame(width: iconSize,height: iconSize)
}
Link(destination: deeplinkURLFirst) {
ZStack {
RoundedRectangle(cornerRadius: 10).foregroundColor(mainColor).frame(width: iconSize,height: iconSize)
}
}.frame(width: .infinity,height: geo.size.height * 0.9,alignment: .leading).background(Color(red: 0.118,green: 0.118,blue: 0.15)).border(Color.white,width: 0).position(x: geo.size.width * 0.5,y: 20)
}
}.frame(maxWidth: .infinity,maxHeight: .infinity).background(Color(red: 0.118,blue: 0.15)).onAppear {
print("all good")
}
}
}
@main
struct WidgetTest: Widget {
let kind: String = WIDGET_PROJECT_NAME
var body: some WidgetConfiguration {
IntentConfiguration(kind: kind,intent: ConfigurationIntent.self,provider: Provider()) { entry in
WidgetTestEntryView(entry: entry)
}
.configurationdisplayName("Favourites")
.description("Fast access to favoutires cagetory.")
.supportedFamilies([.systemMedium])
}
}
struct WidgetTest_Previews: PreviewProvider {
static var previews: some View {
WidgetTestEntryView(entry: SimpleEntry(date: Date(),configuration: ConfigurationIntent()))
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}
extension Image {
init?(base64String: String) {
guard let data = Data(base64Encoded: base64String,options: .ignoreUnkNownCharacters) else { return nil }
guard let uiImage = UIImage(data: data) else { return nil }
self = Image(uiImage: uiImage)
}
}
解决方法
SwiftUI 为您自动布局,它与您应该一次支持所有屏幕的 UIKit 不同,这就是为什么间距会改变但您可以设置“规则”
//Prevents the repeating of code
struct ImageView: View {
var deeplinkURLFirst: URL
let mainColor: Color
//Add another parameter for the image info I counldn't reprodice that
var body: some View {
Link(destination: deeplinkURLFirst) {
ZStack {
RoundedRectangle(cornerRadius: 10)
.foregroundColor(mainColor)
.overlay(
//Keep image within rectangle bounds
//The systemName stuff is just to replicate an actual image fill in with your image code
Image(systemName: "square")
.resizable())
}
}
//Rule
//Keep the images squares or you can set frame using your iconSize
//for all but the size of an iPhone 7 or SE is not the same
//as a ProMax it is best to set a ratio
//If you fix the size padding will have to give way to adjust for larger/smaller screens.
.aspectRatio(1,contentMode: .fit)
}
}
struct WidgetTestEntryView : View {
//var entry: Provider.Entry //I am just working with the View itself not a widget
var deeplinkURLFirst: URL {
URL(string: "\("WIDGET_DEEP_LINK")0")!
}
let iconSize: CGFloat = 75.0
var widgetLabel = "Favourites"
let mainColor = Color(red: 0.218,green: 0.215,blue: 0.25)
let setSpacing: CGFloat = 4
var body: some View {
//Having multiple of GeometryReader just adds to the confusion look at the View as a whole vs pieces
//Less is more with SwiftUI it is meant to support multiple screens
//Set simple rules
GeometryReader { geo in
VStack(spacing: 0) {
//Top portion
HStack(spacing: geo.size.width * 0.4){
Text(widgetLabel).foregroundColor(.white).font(.system(size: geo.size.width * 0.045,weight: .semibold,design: .default))
//The systemName stuff is just to replicate an actual image fill in with your image code
Image(systemName: "square").resizable().foregroundColor(.white)
.frame(width: geo.size.width * 0.15,height: 15,alignment: .center)
}
//Using to many of these will end up causing conflicts
//SwiftUI does a lot of the work for you
.frame(maxWidth: .infinity,maxHeight: geo.size.height * (1/3))
//Rule:
//This will set the space between the boxes
HStack(spacing: setSpacing)
{
//Add another parameter for the image info I counldn't reproduce that without data
ImageView(deeplinkURLFirst: deeplinkURLFirst,mainColor: mainColor)
ImageView(deeplinkURLFirst: deeplinkURLFirst,mainColor: mainColor)
}
//Rule:
//Keep the edge of the boxes from the edge of the screen/HStack
//It is just a minimum so this will give if the space requries it to maintain ratio and spacing between boxes
.padding(setSpacing)
//This might need adjusting but the % of the top + the % of the bottom should == 1
.frame(width: geo.size.width,height: geo.size.height * (2/3),alignment: .center)
//This color needs to be adjusted to the right Color
.background(Color(UIColor.darkGray))
}
}
.background(Color(red: 0.118,green: 0.118,blue: 0.15))
//Just to simualte widget size without crating a widget you shouldn't need it in your actual code
.frame(maxWidth: 350,maxHeight: 150)
.cornerRadius(20)
.onAppear {
print("all good")
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。