Swift 2 is out, and we have to keep up with the times, otherwise we will become an antique. Besides, it is open source, and there is something to do. Being a programmer is really tiring, always chasing, but never catching up. Just when I have a little idea, others step on the accelerator again. This issue has three main contents: Tint Color Build Configurations in Swift Keyboard events Tint Color After iOS 7, UIView added a new tintColor property, which defines a non-default tint color value. The setting of its value will affect the entire view hierarchy with the view as the root view. It is mainly applied to some controls such as app icons, navigation bars, buttons, etc. to obtain some interesting visual effects. The declaration of the tintColor property is as follows:
By default, the tintColor of a view is nil, which means that the view will use the tint color value of the parent view. When we specify the tintColor of a view, this color value is automatically propagated to all subviews in the view hierarchy (with the current view as the root view). If the system does not find a non-default tintColor value in the view hierarchy, the system-defined color value (blue, RGB value [0,0.478431,1], which we can see in IB) is used. Therefore, this value always returns a color value, that is, we did not specify it. Related to the tintColor property is the tintAdjustmentMode property, which is an enumeration value that defines the adjustment mode of the tint color. Its declaration is as follows:
The definition of enumeration UIViewTintAdjustmentMode is as follows:
Therefore, when the tintAdjustmentMode property is set to Dimmed, the color value of tintColor is automatically dimmed. If we do not find a default value in the view hierarchy, the value defaults to Normal. There is also a tintColorDidChange method related to tintColor, which is declared as follows:
This method is automatically called when the tintColor or tintAdjustmentMode property of the view changes. In addition, this method is also called if the tintColor or tintAdjustmentMode property of the parent view of the current view changes. We can refresh our view as needed in this method. Example Next, let’s take a look at the powerful function of tintColor through an example (the example is plagiarized from an example written by Sam Davies, which can be found in iOS7 Day-by-Day :: Day 6 :: Tint Color. I was responsible for moving bricks and implemented it in Swift. The code can be downloaded here). Let’s take a look at the final effect first (the following are all stolen pictures, please forgive me, I’m too lazy): The elements of this interface mainly include UIButton, UISlider, UIProgressView, UIStepper, UIImageView, ToolBar and a custom subview CustomView. Next, let's see what effect changing the view's tintColor will have on these controls. In the viewDidLoad method of ViewController, we set the following:
First, we try to print the default tintColor and tintAdjustmentMode, which output [UIDeviceRGBColorSpace 0 0.478431 1 1] and 1 respectively. This is the output when we do not set any tint color related values for the entire view hierarchy. You can see that although we did not set tintColor, it still returns the system's default value; and tintAdjustmentMode returns the original value of Normal by default. Next, we explicitly set the value of tintAdjustmentMode to Normal and set the image and rendering mode of UIImageView. When we click the "Change Color" button, the following event handling method will be executed:
This code mainly generates a color value randomly and assigns it to the tintColor property of self.view, while updating the tintColor value of the progress bar. Note: The tint color of certain components of some controls is controlled by specific properties. For example, progress has two tint colors: one for the progress bar itself and the other for the background. Click the "Change Color" button to get the following effect: As you can see, we did not manually set the color values of UIButton, UISlider, UIStepper, UIImageView, ToolBar and other subviews in the example, but as the color value of the tintColor attribute of self.view changes, the appearance of these controls also changes. That is to say, the change of the color value of the tintColor attribute of self.view affects the appearance of all subviews in the entire view hierarchy with self.view as the root view. It seems that tintColor is still very powerful. There is also a UISwitch in the interface, which is used to turn on and off the dim tint function. The corresponding processing method is as follows:
When tintAdjustmentMode is set to Dimmed, the actual effect is that the entire color value becomes darker (there is no picture to steal here). In addition, we rewrite the tintColorDidChange method in the subview CustomView to listen to the changes in tintColor to update our custom view. Its implementation is as follows:
Therefore, the color of the box and "Tint color label" changes with the tintColor of the subview, and the tintColor of the subview is inherited from the parent view. In this example, the most interesting part is the image processing. The image processing is relatively simple and crude. For a pixel, if its alpha value is 1, its color is set to tint color; if it is not 1, it is set to transparent. This is how the ninja avatar in the example is processed. However, we need to set the imageWithRenderingMode property of the image to AlwaysTemplate, so that when rendering the image, it will be rendered as a template and its color information will be ignored, as shown in the code: var shinobiHead = UIImage(named: "shinobihead") // Set the rendering mode shinobiHead = shinobiHead?.imageWithRenderingMode(.AlwaysTemplate) Off topic A digression that has little to do with the topic. In color theory, a tint color is a mixture of a color and white. Similar to this are shade color and tone color. Shade color is a mixture of a color and black, and tone color is a mixture of a color and gray. They are all based on Hues. The effects of these color values are shown in the following figure:
For some basic theoretical knowledge, you can refer to Hues, Tints, Tones and Shades: What's the Difference? or some more professional articles. summary If we want to specify the tint color of the entire App, we can set the tint color of the window. In this way, all subviews under the same window will inherit this tint color. When an alert or action sheet pops up, iOS7 will automatically darken the tint color of the view behind it. At this time, we can override the tintColorDidChange method in the custom view to perform the desired operation. Some complex controls can have multiple tint colors, with different tint colors for different parts of the control, such as the UIProgressView mentioned above, as well as navigation bars, tab bars, toolbars, search bars, scope bars, etc. The background tint color of these controls can be handled using the barTintColor property. #p# Build Configurations in Swift In Objective-C, we often use preprocessor directives to help us execute different codes according to different platforms, so that our code supports different platforms, such as:
In Swift, since the support for C language is not as friendly as Objective-C (I don’t know how Swift 2 supports C yet), we cannot use preprocessing instructions as freely and comfortably as in Objective-C. However, Swift also provides its own way to support conditional compilation, using build configurations. Build configurations already include literals true and false, as well as two platform test functions os() and arch(). os() is used to test the system type. The parameters that can be passed in include OSX, iOS, and watchOS. So the above code can be changed to:
Note: In the WWDC 2014 session “Sharing code between iOS and OS X” (session 233), Elizabeth Reid refers to this approach as shimming. Unfortunately, os() can only detect the system type, but not the system version, so these tasks can only be handled at runtime. As for how to detect the system version, Mattt Thompson gave us the answer in his article Swift System Version Checking. Let's take a look at arch(). arch() is used to test the CPU architecture. The values that can be passed in include x86_64, arm, arm64, and i386. It should be noted that arch(arm) will not return true for ARM 64 devices. However, arch(i386) will return true when compiled on a 32-bit iOS simulator. If we want to customize some compilation configuration options used during debugging, we can use the -D flag to tell the compiler. The specific operation is to add the required configuration options in "Build Setting" -> "Swift Compiler-Custom Flags" -> "Other Swift Flags" -> "Debug". If we want to add commonly used DEGUB options, we can add "-D DEBUG" here. In this way, we can perform some different operations in the code for debug and release, such as
Of course, statements can contain 0 or more valid Swift statements, which can include expressions, statements, and control flow statements. In addition, we can also use the && and || operators to combine multiple build configurations, and we can use the ! operator to negate the build configuration, as shown below:
It is important to note that in Swift, conditional compilation statements must be syntactically valid, because Swift will syntax check them even if the code will not be compiled. #p# Keyboard events In interfaces involving form input, we usually need to listen to some keyboard events and perform corresponding operations according to actual needs. For example, when the keyboard pops up, we need to shrink our UIScrollView automatically so that the entire UIScrollView content can be seen. To this end, the following 6 notification constants are defined in UIWindow.h to handle keyboard events at different time points:
Here, I am interested in the order in which keyboard events are called and how to get the size of the keyboard to resize the view appropriately. From the defined keyboard notification types, we can see that we are actually concerned with keyboard events in three stages: display, hide, and size change. Here we set two UITextFields with different keyboard types: one is a normal keyboard and the other is a numeric keyboard. We monitor all keyboard events and print related logs (I won't post the code here) to see the results directly. 1) When we let textField1 get the input focus, the printed log is as follows:
2) Without hiding the keyboard, let textField2 get the focus, and the printed log is as follows:
3) Close the keyboard again, and the printed log is as follows:
From the above log, we can see that no matter whether the keyboard is shown or hidden, a size change notification will be sent, and it will be before the corresponding events of show and hide. When switching between keyboards of different sizes, in addition to sending change events, show events will also be sent (hide events will not be sent). There are two more points to note: If you switch between two keyboards of the same size, no message will be sent. If it is a switch between Chinese and English keyboards in a normal keyboard, as long as the size changes, one or more groups of messages with the same process as 2) above will be sent Knowing the order of event calls, we can decide in which message processing method to perform operations according to our needs. To do this, we need to obtain some useful information. This information is encapsulated in the userInfo of the notification, and the relevant values are obtained through the above constant key. Usually we are concerned about UIKeyboardFrameEndUserInfoKey to obtain the frame of the keyboard after the animation is completed, so as to calculate the height of our scroll view. In addition, we may hope that the change in the height of the scroll view is also transitioned through animation, then UIKeyboardAnimationCurveUserInfoKey and UIKeyboardAnimationDurationUserInfoKey are useful. We can get these values in the following ways:
In fact, there are three other values in userInfo, but these values have been deprecated since iOS 3.2, so we don't need to pay too much attention to them. ***Let's talk about forms. A form interface looks simple, but interactions and UI can always come up with various ways to make it complicated, and there are actually a lot of details designed into it. Financial apps like ours usually involve a lot of form input, so how to do it well still requires some thought. When I'm free, I plan to summarize and write an article. #p# Odds and Ends Customizing UIPickerView's rows The main content of UIPickerView is actually not much, mainly a UIPickerView class and the corresponding UIPickerViewDelegate, UIPickerViewDataSource protocol, which represent the agent and data source respectively. I won't go into details here, just answer a small requirement we encountered. Usually, UIPickerView can define multiple columns, such as year, month, and day. These columns do not interfere with each other and can scroll independently without interfering with others. However, we have a requirement to have three columns, but these three columns need to scroll together. Well, this needs to be handled separately.
We can use this method to customize the view of the row. It's getting late, so I won't say any more nonsense, let's go straight to the code:
We define a PickerViewCell view, which places UILabels in columns equally according to the column parameter we pass in, and sets the text of each UILabel through setLabelTexts. Of course, we can also define the appearance of UILabel in PickerViewCell. It's that simple. However, one thing to note is that although it appears that 3 columns are displayed, it is actually processed as 1 column, so the following implementation should return 1:
Constructing an object of class type '**' with a metatype value must use a 'required' initializer. How to fix the issue of "[AnyObject]? does not have a member named generator" in Swift There is a small requirement to traverse all ViewControllers in the current navigation controller stack. The viewControllers property of the UINavigationController class itself returns an [AnyObject]! array, but since my navigation controller itself may be nil, the ViewController array I get is as follows:
The compiler will report an error with the following prompt:
In fact, this error will be reported whether it is [AnyObject]? or other types such as [String]?. The reason is that the optional type is just a container, it is a different type from the value it wraps, that is, [AnyObject] is an array type, but [AnyObject]? is not an array type. We can iterate an array, but not a non-collection type. There is such an interesting analogy on stackoverflow, I am lazy and just post it here: To understand the difference, let me make a real life example: you buy a new TV on ebay, the package is shipped to you, the first thing you do is to check if the package (the optional) is empty (nil). Once you verify that the TV is inside, you have to unwrap it, and put the box aside. You cannot use the TV while it's in the package. Similarly, an optional is a container: it is not the value it contains, and it doesn't have the same type. empty, or it can contain a valid value. So, the processing here should be:
|
<<: Redefining B2D 0HI.CN will be launched on 36kr crowdfunding platform
>>: Follow the following principles and stop worrying about Xcode code signing issues
How much is the quote for customized fast food in...
[Kinetic Taping Technology] Introduction to Kines...
Can water be turned into "milk"? Of cou...
Content operation is a painful and joyful thing. ...
Financial Academy Hi Research Report 8 Lessons to...
Another "Double Eleven" is coming. Many...
There has never been a lack of great women on the...
Recently, Shao Yiding, chairman of China's la...
The most complete practical tutorial on Baidu Tie...
Over the past few years, Google has made signific...
1 Yuan group purchase· Zebra AI class animal voca...
How would you feel when your phone only has 1% ba...
There are more and more super variety shows movin...
The recent hot weather is really hot. As soon as ...