I am trying to create a WidgetKit extension for one of my apps.
I would like to have a top-aligned label and some dynamic content.
The problem is that all content is centred.
I want the label to be at the top and the container should fill the rest of the space. Within that container are the items (also not centred, starting from the top).
This is my code:
struct WidgetView : View
{
var data: DataProvider.Entry
var body: some View
{
Text("Test")
.font(Font.system(size: 14.0, weight: .medium, design: .default))
.fontWeight(.semibold)
.background(Color.white)
.foregroundColor(Color.red)
.padding(.top, 8.0)
ForEach(0 ..< 2, id: \.self)
{
_ in
Text("This is just some text")
}
}
}
This will result in the following view:
I tried adding a ScrollView and a LazyVStack. Now it looks just like I want it to look, but there is a red circle (probably not allowed in WidgetKit?):
Is this possible? This is my first contact with SwiftUI.
Use VStack with spacer at the bottom
VStack {
Text("Test")
.font(Font.system(size: 14.0, weight: .medium, design: .default))
.fontWeight(.semibold)
.background(Color.white)
.foregroundColor(Color.red)
.padding(.top, 8.0)
ForEach(0 ..< 2, id: \.self)
{
_ in
Text("This is just some text")
}
Spacer()
}
Related
I'm trying to give a shadow to Button using following code.
VStack{
HStack(){
Text("Menu")
.font(.title3)
.fontWeight(.bold)
Spacer()
Image(systemName: "magnifyingglass")
}.padding(.horizontal)
ScrollView(.horizontal){
HStack(){
ForEach(menuOptions, id: \.self){m in
MenuButtons(title:"\(m)")
}
}.frame(height:50)
}
.padding(.horizontal)
.background(.clear)
}.background(.clear)
And my MenuButton struct:
struct MenuButtons: View {
var title: String
var body: some View {
Button(action:{}, label: {
Text(title)
.font(.system(size: 17))
.frame(width:120, height:35)
.cornerRadius(10)
.foregroundColor(Color("secondaryColor"))
.background(Rectangle().fill(.white).shadow(color:.gray,radius:2).cornerRadius(10))
})
}
}
this would be my output:
Expected output:
In above image you can see that shadow is not proper.
How can I achieve the following?
#Dans code works. But its not so much the .tint as the .background of the button, and the order of applying modifiers.
You used a rectangle, then applied shadow, then used cornerRadius. In this order the cornerRadius "cuts off" the shadow applied before.
If you use RoundedRectangle instead (as Dan did) it works fine.
.background(
RoundedRectangle(cornerRadius: 12)
.fill(.white)
.shadow(color:.gray,radius: 2, y: 1)
)
Or you just change the ordering of the modifiers. First cornerRadius, then shadow.
.background(
Rectangle()
.fill(.white)
.cornerRadius(12)
.shadow(color:.gray,radius: 2, y: 1)
)
I believe adding a .buttonStyle(.borderedProminent) and .tint(.clear) may help achieve your desired look. Something like this;
struct ButtonView: View {
let menuOptions = ["Entradas", "Bebidas", "Plato Fuerte", "Postre"]
var body: some View {
VStack{
HStack(){
Text("Menu")
.font(.title3)
.fontWeight(.bold)
Spacer()
Image(systemName: "magnifyingglass")
}.padding(.horizontal)
ScrollView(.horizontal) {
HStack {
ForEach(menuOptions, id: \.self){ m in
MenuButtons(title:"\(m)")
}
}.frame(height:50)
}
.padding(.horizontal)
//.background(.clear)
}//.background(.clear)
}
}
struct MenuButtons: View {
var title: String
var body: some View {
Button(action:{ }, label: {
Text(title)
.font(.system(size: 17))
.frame(width: 120, height: 35)
.cornerRadius(10)
.foregroundColor(.black)
.background(
RoundedRectangle(cornerRadius: 10, style: .circular)
.fill(.white)
.shadow(color: .gray, radius: 2, x: -1, y: 2)
)
})
.buttonStyle(.borderedProminent)
.tint(.clear)
}
}
Result
I am making a list of questions sets and want the whole row to navigate to next view (every row has a different destination view), but only the area next to the text is tappable. I tried creating a SetRow() outside of List and it was working completely fine, but when its inside of List only the empty area is working.
Red is the working area
List code here:
NavigationView {
VStack {
SearchBar(input: $searchInput)
List(viewModel.filterList(by: searchInput)) { setVM in
NavigationLink(destination:
SetView(viewModel: QuestionListViewModel(
emoji: setVM.questionSet.emoji,
title: setVM.questionSet.title,
setID: setVM.questionSet.id)
))
{
SetRow(viewModel: setVM)
}
.onLongPressGesture(minimumDuration: 1) {
selectedSetVM = setVM
showDeleteAlert.toggle()
}
}
.listStyle(PlainListStyle())
}
and SetRow code here:
HStack {
Text(viewModel.questionSet.emoji)
.font(.system(size: 50))
VStack(alignment: .leading) {
Text(viewModel.questionSet.title)
.font(.system(size: 20, weight: .semibold, design: .default))
VStack(alignment: .leading) {
Text("Questions: \(viewModel.questionSet.size)")
.font(.system(size: 15, weight: .light, design: .default))
.foregroundColor(.gray)
Text("Updated: \(viewModel.questionSet.lastUpdated, formatter: taskDateFormat)")
.font(.system(size: 15, weight: .light, design: .default))
.foregroundColor(.gray)
}
}
Spacer()
}
.padding(.top, 10)
The problem comes with your 'longPressGesture' which wants to control the content of your row and listen for longPresses. To avoid this you can use 'onTapGesture' to control the activation of the NavigationLink and 'onLongPressGesture' to activate your actionSheet or Alert.
Here is a short code example that demonstrates the usage:
https://stackoverflow.com/a/67099257
Why is there so much space between the three blue rectangles and the list? How can I remove the space so that all views within the VStack stack at the top? I tried using a Spacer() directly after the List, but nothing changed.
struct ContentView: View {
init() { UITableView.appearance().backgroundColor = UIColor.clear }
var body: some View {
NavigationView {
ZStack {
Color.red
.ignoresSafeArea()
VStack {
HStack {
Text("Faux Title")
.font(.system(.largeTitle, design: .rounded))
.fontWeight(.heavy)
Spacer()
Button(action: {
// settings
}, label: {
Image(systemName: "gearshape.fill")
.font(.system(.title2))
})
}
.padding()
GeometryReader { geometry in
HStack() {
Text("1")
.frame(width: geometry.size.width * 0.30, height: 150)
.background(Color.blue)
Spacer()
Text("2")
.frame(width: geometry.size.width * 0.30, height: 150)
.background(Color.blue)
Spacer()
Text("3")
.frame(width: geometry.size.width * 0.30, height: 150)
.background(Color.blue)
}
}
.padding()
List {
Text("One")
Text("Two")
Text("Three")
Text("Four")
Text("Five")
Text("Six")
}
.listStyle(InsetGroupedListStyle())
}
}
.navigationBarHidden(true)
}
}
}
Bonus question: In web development, you can open your browser's Web Inspector and use the element selector to click on elements which highlights their borders. Useful for something like this where you're trying to figure out which element the offending spacing belongs to. Is there something like that in Xcode?
VStack(spacing: 0) {...}
Spacer()
to your question you can in Xcode use the view inspector. https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ExaminingtheViewHierarchy.html
Since you know that your HStack with the blue rectangles is going to be a height of 150, you should constrain it to that using .frame(height: 150):
GeometryReader { geometry in
...
}
.padding()
.frame(height: 150) //Here
Otherwise, the GeometryReader will occupy all available vertical space.
Re: your web dev comparison, check out the Xcode view hierarchy inspector. It's not exactly the same, but it's in the same vein: https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ExaminingtheViewHierarchy.html
I need to change the size (actually just the height) of the TextField. Using .padding() increases just the area around the TextField, but not the field itself. I've tried some possible solutions:
Change the font size: This approach works, but I don't want to have a TextField with a too large text in itself.
Using custom modifier doesn't work. I get the message Inheritance from non-protocol type 'TextFieldStyle'. Seems to not working in Swift 5 anymore?
My current solution is:
#State private var searchText: String = ""
var body: some View {
HStack{
Image(systemName: "magnifyingglass")
.font(.system(size: 20, weight: .bold))
ZStack(alignment: .leading){
if searchText.isEmpty { Text("search") }
TextField("", text: $searchText,
onEditingChanged: { focused in
if focused {
// do something...
}
},
onCommit: {
// do something...
})
.keyboardType(.alphabet)
.disableAutocorrection(true)
.frame(height: 50)
}
.textFieldStyle(PlainTextFieldStyle())
}
.frame(height: 30)
.frame(maxWidth: .infinity)
.foregroundColor(.white)
.accentColor(.white)
.padding()
.background(
Color("Color-2")
.cornerRadius(20)
.shadow(color: Color.black.opacity(0.3), radius: 5, x: 5, y: 5)
)
.contentShape(Rectangle())
}}
Only the red area is "clickable"
import SwiftUI
struct ContentView: View {
#State var stringOfText: String = ""
var body: some View {
TextField("", text: $stringOfText)
.font(Font.system(size: 50))
.background(Color.yellow)
.foregroundColor(Color.clear)
.cornerRadius(10)
.overlay(Text(stringOfText), alignment: .leading)
.padding()
.shadow(radius: 10)
}
}
How can I insert the preview of a widget into the app?
Can anyone give me some advice?
I did a naive version of a Widget configuration preview using SwiftUI. I used a RoundedRectangle with a small 3D rotation and applied a shadow:
I contained the code inside a custom View called WidgetView:
struct WidgetView<Content: View>: View {
let content: Content
init(#ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 24, style: .continuous)
.fill(Color(.systemBackground))
content
}
.frame(width: 162, height: 162)
.rotation3DEffect(.degrees(10), axis: (x: 1, y: 1, z: 0))
.shadow(color: Color(UIColor.systemGray), radius: 20, x: -5, y: 10)
}
}
The usage is quite simple. Just add the content view you want inside the Widget view:
WidgetView {
HealthActiveEnergyView(entry: ActiveEnergyEntry.mock())
}
.preferredColorScheme(.light)
.previewLayout(layout)
struct HealthActiveEnergyView: View {
var entry: ActiveEnergyEntry
var body: some View {
VStack(alignment: .leading) {
HStack {
Text(NSLocalizedString("Active", comment: ""))
.foregroundColor(entry.configuration.accentColor)
Spacer()
Image(systemName: "flame.fill")
.font(.system(.title))
.foregroundColor(entry.configuration.accentColor)
}
Text(dateFormatter.string(from: entry.date))
.foregroundColor(Color(.systemGray))
.font(.caption)
HStack(alignment: .lastTextBaseline) {
Text("\(entry.totalOfKilocalories)")
.font(.system(.largeTitle, design: .rounded))
.bold()
.foregroundColor(Color(.label))
Text("kcal")
.foregroundColor(Color(.systemGray))
Spacer()
}
Spacer()
Text(NSLocalizedString("AVG 7 DAYS", comment: ""))
.foregroundColor(Color(.systemGray))
.font(.caption)
HStack(alignment: .lastTextBaseline) {
Text("\(entry.avgOfKilocalories)")
.font(.system(.callout, design: .rounded))
.bold()
.foregroundColor(Color(.label))
Text("kcal")
.foregroundColor(Color(.systemGray))
.font(.caption)
Spacer()
}
}
.padding()
}
}