Technology Articles
Technology. It makes the world go 'round. And whether you're a self-confessed techie or a total newbie, you'll find something to love among our hundreds of technology articles and books.
Articles From Technology
Filter Results
Cheat Sheet / Updated 08-12-2022
Windows 365 is Microsoft’s cloud-based operating system that lets you connect to your PC from anywhere in the world with an Internet connection. All you need is a physical device that you can use as a window into your cloud PC and you are good to go. Getting your head around using a PC in the cloud can take some time. It reminds us of the first time we saw the movie The Matrix. In other words, it can be a bit of a mind trip. You are using a physical computer, and then connecting to your cloud PC, and then using your physical computer just like it is your cloud PC. But your cloud PC lives and runs in the cloud, and your physical computer, any physical computer, is just something real you use to connect to your cloud PC and get work done. Like we said, it can take some time to get your head around it.
View Cheat SheetArticle / Updated 08-11-2022
Lists are powerful tools for grouping similar elements, and lists give visitors to your site an easy way to zoom in on groups of information. Just about anything fits in a list, from sets of instructions to collections of links. Definition lists group terms and definitions into a single list and require three elements to complete the list: : Holds the list definitions (dl = definition list) : Defines a term in the list (dt = definition term) : Defines a definition for a term (dd = definition list definition) You can have as many terms (defined by ) in a list () as you need. Each term can have one or more definitions (defined by ). Creating a definition list with two items requires tags and content in the following order: First term name Content for the definition of the first item Second term name Content for the definition of the second item The following definition list includes three terms, one of which has two definitions: Definition Lists Markup Language Definitions SGML The Standard Generalized Markup Language HTML The Hypertext Markup Language The markup language you use to create web pages. XML The Extensible Markup Language The figure shows how a browser displays this HTML. If you think items in a list are too close together, you can use CSS styles to carefully control all aspects of list appearance. Note that definition lists often display differently inside different browsers, and they aren’t always handled the same by search engines or text-to-speech translators. About.com has a nice discussion of definition lists on their Web Design / HTML page. Alas, this means that definition lists may not be the best choice of formatting for lists you create (even lists of definitions). For a more detailed discussion, see the excellent coverage of this topic on Max Design.
View ArticleArticle / Updated 08-10-2022
SwiftUI makes creating your iOS applications easy and efficient. However, there are neat tricks that are not so obvious. Here, you learn some of these tips and tricks so that you can become a better SwiftUI developer. Resume SwiftUI’s live preview My number-one pet peeve about SwiftUI is that the live preview feature in Xcode doesn’t always work. Very often, changes made to your code will cause the automatic previewing feature to pause. Even though your code is perfectly correct and there is no error, the live preview just can’t seem to update automatically. Of course, you could click the Resume button to update the preview, but you waste precious time moving your mouse to click the button. A better way is to press ⌘+Option+P. This causes the live preview to resume and update itself. Now that you know this trick, there is no reason to click the Resume button anymore! You may also want to check out the list of shortcuts for working in Xcode. Combine text views in SwiftUI Here is a neat little trick that you should know if you want to display the various words in a sentence in different colors and sizes. Instead of using the HStack view to group various Text views together, you can simply use the plus (+) operator to add different Text views together, like this: struct ContentView: View { var body: some View { Text("Red ") .foregroundColor(.red) .font(.largeTitle) + Text("Green ") .foregroundColor(.green) .font(.body) + Text("Blue") .foregroundColor(.blue) .font(.title) } } How cool is that? Here’s the output. If you want all the texts to be of the same font size, group them together using a Group view and apply the font() modifier on the Group view: struct ContentView: View { var body: some View { Group { Text("Red ") .foregroundColor(.red) + Text("Green ") .foregroundColor(.green) + Text("Blue") .foregroundColor(.blue) } .font(.largeTitle) } } Create custom modifiers in SwiftUI Swift modifiers allow you to change the behaviors of views. Consider the following example: import SwiftUI struct ContentView: View { var body: some View { VStack { Text("Leonardo da Vinci") .bold() .font(.largeTitle) .foregroundColor(.blue) .shadow(radius: 2) Text("Vincent van Gogh") .bold() .font(.largeTitle) .foregroundColor(.blue) .shadow(radius: 2) } } } Here, you apply the same set of modifiers to the two Text views. You often do that when you want to ensure consistencies in your UI (for example, applying the same set of UI styles when displaying certain information in your application). Instead of repeating the same set of modifiers again and again, wouldn’t it be easier if you could just encapsulate all the modifiers into yet another modifier? What you can do it is create another struct that conforms to the ViewModifier protocol. This protocol requires you to implement a body() method that has a Content parameter. You then apply whatever modifiers you want to this Content argument and return it: import SwiftUI struct Title: ViewModifier { func body(content: Content) -> some View { content .font(.largeTitle) .foregroundColor(.blue) .shadow(radius: 2) } } To use the newly created Title struct on the Text view, apply the modifier() modifier and pass in the Title struct, like this: struct ContentView: View { var body: some View { VStack { Text("Leonardo da Vinci") .bold() .modifier(Title()) Text("Vincent van Gogh") .bold() .modifier(Title()) } } } To make the Title struct look more like a true modifier, create an extension to the View protocol and give it a name — say, titleStyle: import SwiftUI extension View { func titleStyle() -> some View { self.modifier(Title()) } } You can now apply the titleStyle() modifier to the two Text views: struct ContentView: View { var body: some View { VStack { Text("Leonardo da Vinci") .bold() .titleStyle() Text("Vincent van Gogh") .bold() .titleStyle() } } } Display multiple alerts in SwiftUI Usually, in SwiftUI you apply a single alert() modifier to a single view. For example, when the user taps a button, you can display an alert by using the alert() modifier to the button. If you have multiple buttons, you can attach an alert() modifier to each button. However, there are times when you need to display multiple different alerts for a single view. Applying multiple alert() modifiers to a single view will not work correctly, because the last modifier will override the earlier ones. To solve this problem, you can use a single alert() modifier, and use a switch statement within the modifier to decide which alert to display. The following example shows a button that, when it’s clicked, generates a random number of either 1 or 2 and uses it to decide which alert to display: struct ContentView: View { @State private var displayAlert = false @State private var alertToDisplay = 0 var body: some View { Button(action: { self.alertToDisplay = Int.random(in: 1..<3) self.displayAlert = true }) { Text("Display Alert") } .alert(isPresented: $displayAlert) { switch alertToDisplay { case 1: return Alert(title: Text("Alert 1"), message: Text("This is Alert 1")) default: return Alert(title: Text("Alert 2"), message: Text("This is Alert 2")) } } } } Enable debug preview in SwiftUI By default, the preview canvas doesn’t display outputs printed using the print() function. This isn’t useful, however, because often you want to use the print() function as a quick debugging option. The good news is, you can easily fix this. In the preview canvas, right-click the Play button and select Debug Preview. Now if you tap the button, your code will print the output in the Output window: struct ContentView: View { var body: some View { Button ("Tap Me") { print("Button was tapped...") } } } If the Output window is not shown in Xcode, press ⌘+Shift+C and it should appear. Preview your SwiftUI app using different devices You’re familiar with using the preview canvas to preview your app. By default, Xcode automatically picks an appropriate device based on your target. You can preview your app on different modes — light mode and dark mode — using the environment() modifier: struct ContentView_Previews: PreviewProvider { static var previews: some View { Group { ContentView() .environment(\.colorScheme, .light) ContentView() .environment(\.colorScheme, .dark) } } } In addition to previewing in different modes, you can alter the size of the preview window, allowing you to have a glimpse of how your UI will look under different screen dimensions. You can do so using the previewLayout() modifier: static var previews: some View { Group { ContentView() .environment(\.colorScheme, .light) .previewLayout((.fixed(width: 400, height: 600))) ContentView() .environment(\.colorScheme, .dark) } } The image below shows the top preview displaying your UI in a dimension of 400 x 600 pixels. Note that clicking the Live Preview button will revert the preview back to the default size. If you want to preview your UI on multiple devices, you can use a ForEach loop, supply a list of device names, and then use the previewDevice() modifier on the ContentView, like this: static var previews: some View { ForEach(["iPhone 11", "iPhone SE"], id: \.self) { deviceName in ContentView() .environment(\.colorScheme, .light) .previewDevice(PreviewDevice( rawValue: deviceName)) .previewDisplayName(deviceName) } } The following image shows the preview on the iPhone 11 and the iPhone SE. Notice that you can display the name of the device using the previewDisplayName() modifier. Check out the full list of devices that you can preview. Dark mode only works on NavigationView As stated, you can use the environment() modifier to set the preview to dark mode so that you can see how your UI will look like in dark mode. However, it seems like the dark preview mode only works for the NavigationView. For example, consider the following example where you have two Text views contained within a VStack view: import SwiftUI struct ContentView: View { var body: some View { VStack { Text("Leonardo da Vinci") Text("Vincent van Gogh") } } } Suppose you use the environment() modifier to set the preview mode to dark, like this: struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() .environment(\.colorScheme, .dark) } } The words in the Text views automatically change to white, but the background remains white (running on the simulator or an actual device doesn’t have this issue), as shown below. So, essentially, you get a white screen. To fix this problem, wrap the ContentView view using a ZStack and set its background to black, like this: struct ContentView_Previews: PreviewProvider { static var previews: some View { ZStack { Color(.black) ContentView() } .edgesIgnoringSafeArea(.all) .environment(\.colorScheme, .dark) } } The image below shows the text showing up on a black background. Extract subviews in SwiftUI Your UI may contain quite a large number of views. This is very common if you have a complicated UI. However, you can simplify your UI by extracting some of the views as subviews. Consider the following example: import SwiftUI struct ContentView: View { var body: some View { HStack { Image("weimenglee") .resizable() .frame(width: CGFloat(120), height: CGFloat(120)) .cornerRadius(CGFloat(15), antialiased: true) VStack { Text("Wei-Meng Lee") .font(.largeTitle) .bold() Text("Founder") Text("Developer Learning Solutions") .italic() Text("http://calendar.learn2develop.net") Text("@weimenglee") } } } } To break down the UI into smaller subviews so that your UI is more modular and manageable, follow these steps: In the preview canvas, select the Image view and press the ⌘ key. Select Extract Subview. Name the new view PhotoView. The Image view will now be extracted as a new struct named PhotoView: struct ContentView: View { var body: some View { HStack { PhotoView() VStack { Text("Wei-Meng Lee") .font(.largeTitle) .bold() Text("Founder") Text("Developer Learning Solutions") .italic() Text("http://calendar.learn2develop.net") Text("@weimenglee") } } } } struct PhotoView: View { var body: some View { Image("weimenglee") .resizable() .frame(width: CGFloat(120), height: CGFloat(120)) .cornerRadius(CGFloat(15), antialiased: true) } } You can now also extract the VStack and save it as another struct named DetailsView. Now your UI looks like the following, which is more maintainable: struct ContentView: View { var body: some View { HStack { PhotoView() DetailsView() } } } struct PhotoView: View { ... } struct DetailsView: View { var body: some View { VStack { Text("Wei-Meng Lee") .font(.largeTitle) .bold() Text("Founder") Text("Developer Learning Solutions") .italic() Text("http://calendar.learn2develop.net") Text("@weimenglee") } } } Display a context menu in SwiftUI One of the innovative features of iPhone is the support for Haptic Touch (which replaces the 3D Touch on older iPhones). Using Haptic Touch, you can long-press an item on your iPhone and a context-sensitive menu appears (if the app you’re using supports it). You can support this feature in SwiftUI as well. To attach a context menu to a view, use the contextMenu() modifier: To attach a context menu to a view, use the contextMenu() modifier: struct ContentView: View { var body: some View { Image("Mac Pro") .resizable() .frame(width: 300, height: 280) .contextMenu { Button(action: { print("Save Image button tapped...") }) { Text("Save Image") Image(systemName: "tray.and.arrow.down") } Button(action: { print("Add to Cart button tapped...") }) { Text("Add to Cart") Image(systemName: "plus") } } } } To create a context menu, you provide a list of Button views, and the content of each button is automatically wrapped using an HStack view. Now when you long-press the Image view, a context menu appears. Want to learn more? Check out our SwifUI Cheat Sheet.
View ArticleArticle / Updated 08-10-2022
SwiftUI is a declarative programming framework for developing UIs for iOS, iPadOS, watchOS, tvOS, and macOS applications. In fact, SwiftUI was invented by the watchOS group at Apple. Before SwiftUI was introduced, most developers use UIKit and Storyboard (which is still supported by Apple in the current version of Xcode to design a UI. Using UIKit and Storyboard, developers drag and drop View controls onto View Controllers and connect them to outlets and actions on the View Controller classes. This model of building UIs is known as Model View Controller (MVC), which creates a clean separation between UI and business logic. The following shows a simple implementation in UIKit and Storyboard. Here, a Button and Label view have been added to the View Controller in Storyboard; two outlets and an action have been created to connect to them: class ViewController: UIViewController { @IBOutlet weak var lbl: UILabel! @IBOutlet weak var button: UIButton! @IBAction func btnClicked(_ sender: Any) { lbl.text = "Button tapped" } For laying out the views, you use auto-layout to position the button and label in the middle of the screen (both horizontally and vertically). To customize the look and feel of the button, you can code it in the loadView() method, like this: override func loadView() { super.loadView() // background color button.backgroundColor = UIColor.yellow // button text and color button.setTitle("Submit", for: .normal) button.setTitleColor(.black, for: .normal) // padding button.contentEdgeInsets = UIEdgeInsets( top: 10, left: 10, bottom: 10, right: 10) // border button.layer.borderColor = UIColor.darkGray.cgColor button.layer.borderWidth = 3.0 // text font button.titleLabel!.font = UIFont.systemFont(ofSize: 26, weight: UIFont.Weight.regular) // rounder corners button.layer.cornerRadius = 10 // auto adjust button size button.sizeToFit() } The following image shows the button that has customized. UIKit is an event-driven framework, where you can reference each view in your view controller, update its appearance, or handle an event through delegates when some events occurred. In contrast, SwiftUI is a state-driven, declarative framework. In SwiftUI, you can implement all the above with the following statements: struct ContentView: View { @State private var label = "label" var body: some View { VStack { Button(action: { self.label = "Button tapped" }) { Text("Submit") .padding(EdgeInsets( top: 10, leading: 10, bottom: 10, trailing: 10)) .background(Color.yellow) .foregroundColor(Color.black) .border(Color.gray, width: 3) .font(Font.system(size: 26.0)) .overlay( RoundedRectangle(cornerRadius: 10) .stroke(Color.gray, lineWidth: 5) ) } Text(label) .padding() } } } Notice that all the views are now created declaratively using code — no more drag-and-drop in Storyboard. Layouts are now also specified declaratively using code (the VStack in this example stacks all the views vertically). Delegates are now replaced with closures. More important, views are now a function of state (and not a sequence of events) — the text displayed by the Text view is now bound to the state variable label. When the button is tapped, you change the value of the label state variable, which automatically updates the text displayed in the Text view. This programming paradigm is known as reactive programming. The image below shows the various views in action. Want to learn more? Check out our SwiftUI Cheat Sheet.
View ArticleArticle / Updated 08-10-2022
Are you ready to build iOS apps using an innovative and intuitive user interface? Then, SwiftUI is for you! But before you dive in, you’ll need to know about Swift functions. Here’s a quick intro. In Swift, a function is defined using the func keyword, like this: func doSomething() { print("doSomething") } The preceding code snippet defines a function called doSomething. It does not take in any inputs (known as parameters) and does not return a value (technically, it does return a Void value). To call the function, simply call its name followed by a pair of empty parentheses: doSomething() Understanding input parameters A function can also optionally define one or more named typed inputs. The following function takes in one single typed input parameter: func doSomething(num: Int) { print(num) } To call this function, call its name and pass in an integer value (known as an argument) with the parameter name, like this: doSomething(num: 5) The following function takes in two input parameters, both of type Int: func doSomething(num1: Int, num2: Int) { print(num1, num2) } To call this function, pass it two integer values as the argument: doSomething(num1: 5, num2: 6) Returning a value Functions are not required to return a value. However, if you want the function to return a value, use the -> operator after the function declaration. The following function returns an integer value: func doSomething(num1: Int, num2: Int, num3: Int) -> Int { return num1 + num2 + num3 } You use the return keyword to return a value from a function and then exit it. When the function returns a value, you can assign it to a variable or constant, like this: var sum = doSomething(num1:5, num2:6, num3: 7) Functions are not limited to returning a single value. In some cases, it’s important for functions to return multiple values (or even functions). In Swift, you can use a tuple type in a function to return multiple values. Want to learn more? Check out these SwiftUI tips and tricks.
View ArticleArticle / Updated 08-10-2022
Video reports and audience retention graphs are designed to help you understand how well your viewers are responding to your YouTube channel content. To find out who’s watching your YouTube videos, you have to try a different tack: check out YouTube’s audience reports. Diving into YouTube’s demographics metrics It helps to know who’s watching your YouTube content so that you can make important content-planning decisions. The Audience tab of YouTube Analytics is a fascinating way to analyze your channel demographics, because you can get concrete information about your audience members’ gender, age, and country of residence. Certain audience reports allow you to filter to see results explicitly from your subscriber base. Sometimes, it’s interesting to see whether your subscriber demographics mirror your general audience demographics. To access audience reports, follow these steps: Go to YouTube. Log on to your YouTube account.If you see the blue Sign In button in the top right corner of the YouTube home page, enter your email address and password. Click the Logged-In icon and choose YouTube Studio from the menu that appears.The YouTube Studio navigation menu should appear on the left side of your browser. Choose Analytics from the navigation menu. Click to open the Audience tab on the Reports menu.Here you find summary reports of age and gender. Click the See More link at the bottom of the Age and Gender summary report, and examine the charts and their accompanying details.It’s terrific if your audience is exactly what you thought it would be. If it isn’t, revisit your assumptions. You may find that your content is having wider interest, which may be a good thing. Conversely, if you’re not seeing enough traction, perhaps you’re not engaging enough with key creators and fans in your core demographic to help you get the word out. Refine the report to show only subscribed viewers by choosing Subscription Status from the filter drop-down menu.Look closely at how the graphs change. If you see a big difference, determine whether subscription requests are working more broadly than expected, because your content certainly is appealing to others. Make it a habit to compare your demographic information over time to detect any shifts in your audience. Diving into YouTube subscribers metrics Knowing your YouTube subscribers’ patterns and where they’re doing their subscribing is an important part of your channel management responsibilities. YouTube is well aware of that, which is why it offers a subscription source report as part of YouTube Analytics. Here’s how to access it: Go to YouTube. Log on to your YouTube account.If you see the blue Sign In button in the top right corner of the YouTube home page, enter your email address and password. Click the Logged-In icon and choose YouTube Studio from the menu that appears.The YouTube Studio navigation menu should appear on the left side of your browser. Bring up the Analytics section of YouTube Studio. Click on Advanced Mode from the top right of the screen.Within the Advanced Mode window, click on More from the Reports menu and find the Subscription Source option. Look at the report’s table section to see where on YouTube your audience subscribes to your channel.In addition to subscriber gains, you see the number of subscribers lost, too, which is a normal part of channel activity. Interested in learning more? Check out our YouTube Channels Cheat Sheet.
View ArticleArticle / Updated 08-10-2022
Swift is a type-safe language, which means that the programming language makes it clear to you the types of values your code is working with. The following article discusses how to declare constants and variables and how to work with strings and comments when programming with Swift. Swift constants In Swift, you create a constant using the let keyword: let radius = 3.45 // Double let numOfColumns = 5 // Int let myName = "Wei-Meng Lee" // String Notice that there is no need to specify the data type — the data types are inferred automatically. If you want to declare the type of constant, you can do so using the colon operator (:) followed by the data type, as shown here: let diameter:Double = 8 After a constant is created, you can no longer change its value. Always use a let when you need to store values that do not change. Swift variables To declare a variable, you use the var keyword: var myAge = 25 var circumference = 2 * 3.14 * radius After a variable is created, you can change its value. In Swift, values are never implicitly converted to another type. For example, suppose you’re trying to concatenate a string and the value of a variable. In the following example, you need to explicitly use the String() function to convert the value of myAge to a string value before concatenating it with another string: var strMyAge = "My age is " + String(myAge) To get the text representation of a value (constant or variable), you can also use the description property, like this: myAge.description. Swift strings One of the common tasks in programming is inserting values of variables into a string. In Swift, you use string interpolation and it has the following format: "Your string literal \(variable_name)" The following statement shows an example: let firstName = "Wei-Meng" let lastName = "Lee" var strName = "My name is \(firstName) \(lastName)" You can also use this method to include a Double value in your string (or even perform mathematical operations or function calls): var strResult = "The circumference is \(circumference)" Swift comments In Swift, as in most programming languages, you insert comments into your code using two forward slashes (//): // this is another comment If you have several lines of comments, it’s better to use the /* and */ combination to denote a block of statements as comments: /* this is a comment this is another comment */ Want to learn more? Check out our SwiftUI Cheat Sheet.
View ArticleArticle / Updated 08-10-2022
One important feature in Swift is closure. Closures are self-contained blocks of code that can be passed to functions to be executed as independent code units. Think of a closure as a function without a name. In fact, functions are actually special cases of closures. Swift offers various ways to optimize closures so that they’re brief and succinct. The various optimizations include the following: Inferring parameter types and return types Implicit returns from single-statement closures Shorthand argument names Trailing closure syntax Operator closure Understanding Swift closures The best way to understand Swift closures is to use an example. Suppose you have the following array of integers: let numbers = [5,2,8,7,9,4,3,1] Assume you want to sort this array in ascending order. You could write your own function to perform the sorting, or you could use the sorted() function available in Swift. The sorted() function takes two arguments: An array to be sorted A closure that takes two arguments of the same type as the array and returns a true if the first value appears before the second value Using Swift functions as closures In Swift, functions are special types of closures. As mentioned, the sorted() function needs a closure that takes two arguments of the same type as the array, returning a true if the first value appears before the second value. The following Swift function fulfils that requirement: func ascending(num1:Int, num2:Int) -> Bool { return num1 The ascending() function takes two arguments of type Int and returns a Bool value. If num1 is less than num2, it returns true. You can now pass this function to the sorted() function, as shown here: var sortedNumbers = numbers.sorted(by: ascending) The sorted() function now returns the array that is sorted in ascending order. The sorted() function does not modify the original array. It returns the sorted array as a new array. Assigning Swift closures to variables As mentioned earlier, functions are special types of closures. In fact, a closure is a function without a name. However, you can assign a closure to a variable — for example, the ascending() function discussed earlier can be written as a closure assigned to a variable: var compareClosure : (Int, Int)->Bool = { (num1:Int, num2:Int) -> Bool in return num1 < num2 } To use the compareClosure closure with the sorted() function, pass in the compareClosure variable: sortedNumbers = numbers.sorted(by: compareClosure) Writing Swift closures inline You can pass a function into the sorted() function as a closure function, but a better way is to write the closure inline, which obviates the need to define a function explicitly or assign it to a variable. Rewriting the earlier example would yield the following: sortedNumbers = numbers.sorted(by: { (num1:Int, num2:Int) -> Bool in return num1 < num2 } ) As you can see, the ascending() function name is now gone; all you’ve supplied is the parameter list and the content of the function. If you want to sort the array in descending order, you can simply change the comparison operator: sortedNumbers = numbers.sorted(by: { (num1:Int, num2:Int) -> Bool in return num1 > num2 } ) Understanding type inference Because the type of the first argument of the closure function must be the same as the type of array you’re sorting, it’s actually redundant to specify the type in the closure, because the compiler can infer that from the type of array you’re using: var fruits = ["orange", "apple", "durian", "rambutan", "pineapple"] print(fruits.sorted(by: { (fruit1, fruit2) in return fruit1 If your closure has only a single statement, you can even omit the return keyword: print(fruits.sorted(by: { (fruit1, fruit2) in fruit1 Using shorthand argument names Above, names were given to arguments within a closure. In fact, this is also optional, because Swift automatically provides shorthand names to the parameters, which you can refer to as $0, $1, and so on. The previous code snippet could be rewritten as follows without using named parameters: print(fruits.sorted(by: { $0<$1 }) ) To make the closure really terse, you can write everything on one line: print(fruits.sorted(by:{ $0<$1 })) Working with Swift’s operator function You saw that the closure for the sorted() function was reduced to the following: print(fruits.sorted(by:{ $0<$1 })) One of the implementations of the lesser than (<) operator is actually a function that works with two operands of type String. Because of this, you can actually simply specify the < operator in place of the closure, and the compiler will automatically infer that you want to use the particular implementation of the < operator. The preceding statement can be reduced to the following: print(fruits.sorted(by:<)) If you want to sort the array in descending order, simply use the greater than (>) operator: print(fruits.sorted(by:>)) Using trailing closures in Swift Consider the closure that you saw earlier: print(fruits.sorted(by: { (fruit1, fruit2) in return fruit1 Notice that the closure is passed in as a second argument of the sorted() function. For long closures, this syntax may be a little messy. If the closure is the final argument of a function, you can rewrite this closure as a trailing closure. A trailing closure is written outside of the parentheses of the function call. The preceding code snippet, when rewritten using the trailing closure, looks like this: print(fruits.sorted() { (fruit1, fruit2) in return fruit1 Using the shorthand argument name, the closure can be shortened to the following: print(fruits.sorted(){$0<$1}) Want to learn more? Check out our SwiftUI Cheat Sheet.
View ArticleArticle / Updated 08-10-2022
To animate a view in SwiftUI, apply the animation() modifier on it. SwiftUI animates any changes made to animatable properties of a view. For example, the various properties of a view in SwiftUI — such as its color, opacity, rotation, size, and other properties — are all animatable. As usual, the best way to understand this concept is to use an example. First, create a rounded button that shows the Confirm caption: struct ContentView: View { var body: some View { Button(action: { }) { Text("Confirm") .bold() } .padding(40) .background(Color.green) .foregroundColor(.white) .clipShape(Circle()) } } Apply some scaling (zooming) to the button using the scaleEffect() modifier: struct ContentView: View { @State private var scaleFactor: CGFloat = 1 var body: some View { Button(action: { }) { Text("Confirm") .bold() } .onAppear(perform: { self.scaleFactor = 2.5 }) .padding(40) .background(Color.green) .foregroundColor(.white) .clipShape(Circle()) .scaleEffect(scaleFactor) } } What you want to do here is zoom the button to two and a half times its original size. The scaling will be performed as soon as the Button view is shown in SwiftUI. The following image shows the button zoomed in to two and a half times its original size when it first appears. What you really want is to slow down the scaling, so that users can see the zooming-in process. For this, you can use the animation() modifier on the Button view: struct ContentView: View { @State private var scaleFactor: CGFloat = 1 var body: some View { Button(action: { }) { Text("Confirm") .bold() } .onAppear(perform: { self.scaleFactor = 2.5 }) .padding(40) .background(Color.green) .foregroundColor(.white) .clipShape(Circle()) .scaleEffect(scaleFactor) .animation(.default) } } The .default property actually belongs to the Animation struct, so you can rewrite the above statement as follows: .animation(Animation.default) When you now load the Button view again, the button zooms in two and a half times. Specifying the type of animation in SwiftUI By default, the button will zoom in at a linear speed. You can also use the easeInOur() modifier if you want the animation to start slow, pick up speed, and then slow down again: .animation( .easeInOut(duration: 2) ) The duration parameter indicates how much time is given for the animation to complete in SwiftUI. In this example, the zoom animation must complete in two seconds. If you want to start fast and then slow down, use the easeOut() modifier: .animation( .easeOut(duration: 2) ) Both the easeInOut() and easeOut() modifiers are type methods of the Animation struct. Repeating the animation in SwiftUI Many times, you want the animation to repeat a number of times. For this you can apply the repeatCount() modifier: .animation( Animation.easeInOut(duration: 2) .repeatCount(2, autoreverses: true) ) The easeInOut() is a type method of the Animation struct, and it returns an Animation struct. So, in this case, you call the repeatCount() modifier of the Animation struct to repeat the animation a number of times (twice, in this case). The autoreverses parameter allows you to reverse the animation, so for this particular case the size of the button changes from small to big, and then reverses and changes from big to small. The image below shows the animation that is repeated twice. Notice that at the end of the second animation, the button reverts back to the larger size as specified in the scaleFactor state variable: .scaleEffect(scaleFactor) // changed to 2.5 in onAppear() If you want the animation to repeat forever, use the repeatForever() modifier: .animation( Animation.easeInOut(duration: 2) .repeatForever(autoreverses: true) ) Stopping the animation in SwiftUI Although you can animate nonstop in SwiftUI, there are times where you need to stop the animation. Here’s another example: struct ContentView: View { @State private var opacity:Double = 1.0 var body: some View { Button(action: { }) { Text("Click Me") .fontWeight(.bold) .font(.title) .foregroundColor(.blue) .padding() .background(Color.yellow) .overlay( Rectangle() .stroke(Color.blue, lineWidth: 5) ) .opacity(opacity) .onAppear() { let baseAnimation = Animation.linear(duration: 1) withAnimation ( baseAnimation.repeatForever( autoreverses: true)) { self.opacity = 0.2 } } } } } The preceding code snippet shows a Button view with its opacity initially set to 1.0. When it appears, you perform a linear animation (animating with constant speed) to change the opacity of the button down to 0.2, all within a duration of 1 second. In the next 1 second, it then changes to fully opaque again. Unlike the earlier example, this example does not use the animation() modifier for animation. Instead, you use the withAnimation block. The withAnimation block lets you explicitly tell SwiftUI what to animate. The image below shows the button fully opaque when it’s loaded and then gradually changes its opacity to 0.2. The animation is perpetual, so to stop it, you need to do some work in SwiftUI. For this, you can use a Boolean state variable (let’s call it animate) and use it to determine if the animation should continue: withAnimation (self.animate ? baseAnimation.repeatForever( autoreverses: true) : Animation.default) { self.opacity = 0.2 } In the preceding Swift code snippet, if the animate state variable is true, you’ll perform the animation perpetually, or you can set the animation to default (which will only perform the animation once). The following code snippet stops the animation when the button is tapped and sets the opacity of the button back to 1: struct ContentView: View { @State private var opacity:Double = 1.0 @State private var animate = true var body: some View { Button(action: { self.animate = false self.opacity = 1.0 }) { Text("Click Me") .fontWeight(.bold) .font(.title) .foregroundColor(.blue) .padding() .background(Color.yellow) .overlay( Rectangle() .stroke(Color.blue, lineWidth: 5) ) .opacity(opacity) .onAppear() { let baseAnimation = Animation.linear(duration: 1) withAnimation (self.animate ? baseAnimation.repeatForever( autoreverses: true) : Animation.default) { self.opacity = 0.2 } } } } } Remember to follow the Apple Human Interface Guidelines (HIG) when it comes to animating your UI. This also applies to custom animations. Want to learn more? Check out these SwiftUI resources.
View ArticleArticle / Updated 08-10-2022
The bad news is that every new SketchUp user encounters certain problems, usually in the first couple hours of using the software. You can call these problems growing pains. The good news is that, because these SketchUp problems are common, you can anticipate a lot of the bad stuff you’ll go through. This article offers you SketchUp tips and tricks to help you work around those issues. SketchUp won’t create a face where you want it to You’ve dutifully traced all around where you want SketchUp to create a face, but nothing’s happening. If you follow along in the image below, which was inspired by a visit to the M.C. Escher museum in Amsterdam, you see the top-left image seems to show a cube beside a rectangle, but the rectangle didn’t produce a face. In the top-right image, a diagonal line was drawn between diagonally opposite corners of the rectangle, producing two triangular faces, but something still doesn’t look right. Changing the camera position to standard front (lower-left image) and right side (lower-right image) reveals the source of the problem. It turns out that the upper-right corner of the rectangle doesn’t lie on the red-blue plane but is actually to the right of the blue-green plane, and to the right of the blue-red plane. The upper-left image isn’t really an optical illusion; it just looks like one. Ninety percent of the time, when SketchUp doesn’t create a face where you think it should, an edge isn’t on the plane you think it’s on. To check whether your edges are coplanar, draw an edge that cuts diagonally across the area where you want a face to appear. If a face appears now, your edges aren’t all on the same plane. To fix the problem, you have to figure out which edge is the culprit, and the Color By Axis option may help you see this information at a glance. Here’s how Color By Axis works: In the Styles panel, change your edge color from All Same to By Axis.SketchUp draws the edges in your model using the color of the axis to which they’re parallel; edges parallel to the red axis are red, and so on. Look carefully at the edges that you wanted to define your desired face.Are all the edges the color they’re supposed to be? If they’re not all supposed to be parallel to the drawing axes, this technique doesn’t do much good. But if they are, and one (or more) of them is black (instead of red or green or blue), that edge (or those edges) is your problem child. Fix it and switch back to All Same when you’re done. If the plane isn’t the problem with your edges, then check whether one edge is part of a separate group or component. To check whether you have a component problem, try hiding groups or components and checking the edges to make sure that they’re all in the group or component you think they’re in. A common source of this problem is SketchUp’s inferences. As you slide the mouse over a face you may unwittingly be latching on to an unintended inference, such as the edge of a surface that is part of a cylinder. Watch those inference prompts, and use Undo when you complete a face but no face appears. Your SketchUp faces are two different colors In SketchUp, faces have two sides: a front and a back. By default, these two sides are different colors. When you use certain tools, such as Push/Pull or Follow Me, on a face, sometimes the faces on the resulting geometry are “inside out.” For some people, the issue is just bothersome. If you want to 3D-print your model, you need to fix the issue so that your model will print correctly. To fix this issue, right-click the faces you want to flip and choose Reverse Faces from the context menu. If you have lots of faces to flip, you can select them all and then choose Reverse Faces to flip them all at once. In 3D printing, this process is called checking your model’s normals. The plan for the structure you see below was for all the outside walls to be wood siding and the interior walls to be painted yellow. But the top two images show that somehow the left wall got reversed. The bottom two images show that the problem has been solved by selecting the yellow face and reversing it. Edges on a face won’t sink in Edges on a face tend not to sink in when you’re trying to draw a rectangle (or another geometric figure) on a face with one of SketchUp’s shape-drawing tools. Ordinarily, the Rectangle tool creates a new face on top of any face you use it on; after that, you can use Push/Pull to create a hole, if you want. When the edges you just drew don’t seem to cut through the face you drew them on, try these approaches: Retrace one of the edges. Sometimes that works — you’d be surprised how often. Select Hidden Geometry from the View menu. You’re checking to make sure that the face you just drew isn’t crossing any hidden or smoothed edges; if it is, the face you thought was flat may not be. Make sure that the face you drew on isn’t part of a group or component. If it is, undo a few steps and then redraw your shape while you edit the group or component. Select the face + edges, right-click, and choose Intersect Faces→With Selection. This approach is often needed when you are working with one or more curved surfaces. SketchUp crashed, and you lost your model Unfortunately, SketchUp crashes happen sometimes. The good news is that SketchUp automatically saves a copy of your file every five minutes. In the web version, these autosaves are captured in Trimble Connect as revisions. You can always view the revision history for a file by navigating to it in the Trimble Connect tab (by clicking Open in the menu at the top of the screen to access Trimble Connect). For any file, you can choose to view or restore an older version. In desktop versions, the file that SketchUp autosaves is actually a separate file, AutoSave_yourfilename.skp. If your file ever gets corrupted in a crash, an intact file is ready for you. The problem is that most people don’t even know that the autosaved file is there. Where do you find it? If you’ve ever saved your file, the autosaved file is in the same folder as the original; therefore, it’s very important that you save your file almost immediately after starting it. Simple, right? Not so fast. On a Mac, you may need to change your Library folder from hidden to visible. In the Finder app, hold down the Option key while you choose Go→Library. If you don’t hold down the Option key, Library may not appear on the menu. When you close your model, SketchUp typically assumes nothing untoward has happened and usually cleans up after itself by deleting the autosaved file. The really good news is that every time you save a file, SketchUp proactively saves two identical files, one with the normal file extension .SKP and the other with the file extension .SKB. You continue working on the .SKP file. If something goes really wrong with your model, you can always go back to how it was an instant before the last time you saved it. But you can’t find it in the Open File dialog box. Here’s the secret: In the Open File dialog box, go to the end of the File Name window, click the down arrow beside Sketchup Models (.SKP), and click All Files. Now the .SKB files show, and you can open them. (web: The same basic principles apply, but read more details on SketchUp's website.) To minimize the amount of work you lose when software (or hardware) goes south, always do two things: Save often — compulsively, even. Use the Save a Copy As command on the File menu. When you’re working on a big project, the following steps can help ensure you don’t lose any work: Save the original version of your file as yourfilename_Master.skp.That’s the file you’ll always be working on. Create a folder that lives in the same place as your Master file; call the folder something like Your file’s name Archive. Every half-hour or so, choose File→Save a Copy As, and save a sequentially numbered version of your file to the Archive folder.When you’re building a big model, it’s not uncommon for your Archive folder to contain 40 or 50 saved versions of the model dating back to when the project first started. Back up regularly.At least at the end of every work session, such as when you head to a coffee or lunch break, back up your files to a low-cost, high-capacity, high-speed portable USB drive, then remove it and keep it separate from your computer. At the end of your shift, take it to a different location. You don’t need to keep it in a bank vault, just in a separate building. Take it home at night, for example. You can always buy new hardware and software, but you can’t buy your personal files. SketchUp is sooooo slooooooooow The bigger your SketchUp model, the worse your computer’s performance. What makes a model big? In a nutshell, faces. Do everything in your power to keep your model as small as you can. Here are some tips for doing that: Reduce the number of sides on your extruded circles and arcs. Use 2D people and trees instead of 3D ones. 3D plants and people have hundreds of faces each. Consider using 2D ones instead, especially if your model won’t be seen much from overhead. Use search filters in 3D Warehouse. When you’re searching for models in 3D Warehouse, you can restrict your search result to show only models of a certain file size or polygon (face) complexity. Especially if your model is more than 10 MB, it makes sense to keep your 3D Warehouse downloads small! Some models are just big, and you can’t do much about it. Here are some tricks for working with very large SketchUp models: Make liberal use of the Outliner and tags. These SketchUp features were specifically designed to let you organize your model into manageable chunks. Hide everything you’re not working on at the moment; doing so gives your computer a fighting chance. Substitute simple forms for large numbers of complex components. For example, insert sticks as placeholders for big sets of 3D trees, cars, and other big components. Turn off shadows and switch to a simple style, such as Shaded in the Default Styles collection. It takes a lot of computer horsepower to display shadows, edge effects, and textures in real time on your monitor. When you’re working, turn off all that stuff. Use scenes to navigate between views. Scenes aren’t just for presenting your model; they’re also great for working with it. If you create scenes for the different views you commonly use and with different combinations of hidden geometry, then you don’t have to orbit, pan, and zoom around your gigantic model. To speed up things even more, deselect Enable Scene Transitions in the Animation panel of the Model Info dialog box. (web: Animation settings are in the Scenes panel.) You can’t get a good view of the inside of your SketchUp model It’s not always easy to work on the inside of something in SketchUp. You can do these things to make it easier, though: Cut into your model with section SketchUp’s Sections feature lets you cut away parts of your model — temporarily, of course — so that you can get a better view of what’s inside. Widen your field of view. Field of view is the part of your model you can see onscreen at one time. A wider FOV is like having better peripheral vision. You can change the field of view only when in Perspective view mode, but the setting will be remembered if you then switch to Parallel view mode. The image below shows the plan view of a room. If you zoom or walk in through the door — oops, tunnel vision. Increase peripheral vision by changing your field of view. Ah, that’s better! Now you can see that the picture hanging on the wall is the floor plan of this room. A face flashes when you orbit in SketchUp If you have two faces in the same spot — maybe one is in a separate group or component — you see a Z-fighting effect. SketchUp is deciding which face to display by switching back and forth between them; it’s not a good solution, but certainly a logical one — at least for a piece of software. The image below attempts to portray this effect in a single image. The only way to get rid of Z-fighting is to delete or hide one of the faces. You can’t move your SketchUp component the way you want When you insert some components into your model, the components by default glue to faces. A glued component instance isn’t actually glued in one place. Instead, it’s glued to the plane of the face you originally placed (or created) it on. For example, if you place a sofa component on the floor of your living room, you can move it around only on that plane — not up and down. This gluing behavior comes in handy when you deal with things like furniture; it allows you to rearrange things with the Move tool without accidentally picking them up. If you can’t move your component the way you want to, right-click it to see whether Unglue is an option; if it is, choose it. Now you can move your component around however you want. Bad stuff happens almost every time you use SketchUp’s Eraser When you use the Eraser tool, it’s pretty easy to delete stuff accidentally. Worse, you usually don’t notice what’s missing until it’s too late. Here are some tips for erasing more accurately: Orbit around. Try to make sure that nothing is behind whatever you’re erasing; use SketchUp’s navigation tools to get a view of your model that puts you out of danger. Switch on Back Edges. When you’re doing a lot of erasing, choose View→Edge Style→Back Edges. That way, you can see every edge in your model, and you’re less likely to erase the wrong ones. Use the Undo modifier of the eraser. Follow along starting in the upper-left image you see below. The intent is to erase the four edges in the center to create a single face. While erasing, you can select multiple objects by holding down the left mouse button while dragging the eraser over them. Oh, great googly moogly (or words to that effect) — you selected some things you didn’t want to erase. No problem: Don’t release the mouse button, but press and hold down the keyboard Alt key (Mac: ⌘). Now anything you drag the eraser over will be unselected. You can switch back and forth as desired, but nothing actually gets erased until you release the mouse button. Double-check. After you do a lot of erasing, give your model a quick once-over with the Orbit tool, just to make sure that you didn’t get rid of anything important. Put a sticky note on your computer monitor that says something like Check after Erase! just to remind you. All your edges and faces have different tags Using Tags in SketchUp can be a dangerous business. Here’s the short version of some good advice: Always build everything on Untagged, and assign whole groups or components to other tags only if you really need to. If you used tags in SketchUp and now things are messed up, here’s what you can do to recover: Make sure that everything is visible.Select Hidden Geometry on the View menu; then (in the Tags panel) make all your tags visible. Just make sure that you can see everything in your model. Choose Edit→Select All. In the Entity Info panel, move everything to Layer0. In the Tags panel, delete your other tags. When you’re prompted, tell SketchUp to move anything remaining on them to Untagged. Create new tags and follow best practices to avoid problems. If you’ve downloaded 3D Warehouse models, you’ll probably find that they have some tags that you don’t understand and might want to get rid of. They may have had significance to the original creator, but they can become clutter in your file, so they should be removed. Want to learn more? Check out our SketchUp Cheat Sheet.
View Article