About light and green awn

Qingmanread is an app THAT I open every day. Among the more than 200 channels it provides, I have subscribed to more than a dozen of them, and I like this product very much. The creator of the product is Wang Junyu, who founded an even more famous company, Wandoujia. For more information about Light Mang and Jun Yu, please refer to The report on Frontier Technology. Although the report emphasized that light mang is not green mang, but referring to the relationship between cicada and Zhihu, I still decided to name my client green mang. And named green awn a big advantage is logo good design. On the second day after finishing the prototype, I asked Joseph, a non-famous designer, to help me design a logo, which I personally think is very good.

Logo designed by Joseph, not famous designer

Logo designed by Joseph, not famous designer

Why do you want to do green awn

On August 18th, WHEN I was strolling around github, I found the API document of The Light Mang team that was still in the internal beta stage. With an attitude of trying it out, I sent an email to the light Mang team to apply for internal beta. Two days later, I got a reply from zhenhui, the product manager of the light Mang team, who agreed to my application for internal beta. After receiving the email, I was very excited. Although I had made clients like Weibo, Twitter and Instagram before, these products had already been put on the Apple Store with better products than mine. It is estimated that no one except me would use the simple version of the client I developed. On the other hand, there is no MAC or Windows client.

In macOS and Windows, I estimate that there will be a large number of macOS users, so I choose macOS platform. I think this is an opportunity for me, and there may be a lot of people trying this software. After all, it’s rewarding to see your software running on someone else’s computer or phone. (smile)

According to incomplete statistics, more than 100 people have downloaded the software since it became open source.

How is green Awn made

Cicada is the MAC client of Zhihu Daily. Qingmang and Cicada have the same needs, namely, to display the three parts of channel List, article List and article Content. Therefore, I had the idea of learning from Cicada. After searching around, I found that there was no similar MAC software available on Github, so I decided to write it from scratch and the first thing I did was open source it. I believe that the application of the three-stage layout can be used in many scenarios and can give some inspiration to beginners. Welcome to fork and Star on github. Special thanks to github developers @jydemo and @Immress for the improvements and code implementation of this project. The renderings are shown below.

Client view (parody cicada)

Client view (parody cicada)

Notification Center view (slightly ugly)

Notification Center view (slightly ugly)

TouchBar view

TouchBar view

The lightweight API follows an RPC style, shaped like a domain name/principal. Operations, bodies, and operations all use a lower case hump nomenclature, which is generally easier to call. List, category. Get, article. List, article. After testing, it is found that the internal beta version provides very limited channels, only 11 channels, so now I choose to show all channels.

In the process of developing Green Awn, the following technologies were used: HTTP request, JSON parsing, NSSplitView, WebKit, NSTableView, Multithreading (GCD), imageView, custom NSTextField, NSScrollView, custom Window, NSTouchBar, NCWidge TProviding and other technology, I will introduce the process of green mang realization in detail.

Interface part

How to build macOS/ios interfaces has always been a topic of debate, and there are generally three options:

  1. Pure code handwriting
  2. Xib file
  3. Stroyboard

Pure handwritten code

Pure handwritten code is the best choice for geeks, and it is a good choice for multi-person collaborative work. However, the main disadvantages are that the effect cannot be seen intuitively and the encoding speed is very slow. For example, it may take 20 lines of code to initialize a custom Button, which is very difficult to read.

Xib file

Xib solves both of these problems and improves development efficiency. Xibs are actually XML files that are compiled into Nib files during compilation, and each Nib file is associated with the corresponding ViewController. The downside of xiBs is that the code may override the DESIGN of the UI, and each view requires a single Xib, and the jump between views still requires code control.

Stroyboard

To solve the Xib problem, Apple provides storyboarding. A StoryBoard can be seen as bringing together a bunch of XIBs, telling a story, and clearly seeing the jump relationship between each ViewController without writing any code. Therefore, I chose StoryBoard to construct Qingawn.

Screenshot of Qingmang’s StoryBoard file

Screenshot of Qingmang’s StoryBoard file

From the screenshot of StroyBoard, you can clearly see the layout of the entire interface. The layout of the entire interface is made by imitating the Mac client of Zhihu Daily (Cicada). The classic three-stage layout, NSSplitView can divide the interface into two parts: left and right (or up and down). Considering that the topic column is narrow and the topic has a strong relationship with the articles under the corresponding topic, SplitView is used to split the Overview Controller in two and the three-section layout is complete.

Start with the OverView view on the left. This view consists of two parts. The first part is a series of theme buttons. After clicking on the latest article list, use a WebView in the DetailView on the right to display the details of the article.

The black part is the view of TouchBar, which is a new interactive device added by Apple on MacBook Pro 2016. There are a lot of discussions about TouchBar, and we can talk about it individually when we are free. However, in order to respect this 4K bar, I still decide to adapt it accordingly. The theme is put on Bar in the form of buttons. The button on Bar and the OverView button need to do linkage function, which will be mentioned in the following article.

By patiently dragging in related controls and controlling their relative positions, the initial prototype is complete. Of course, after trial, you can still find the optimized part, such as Overview tableView is not top to the window title, so that the user drags that part, the window can still move, the same, WebView is also required to leave white. It’s just a small detail, but it’s really pleasing to users.

Customizations replace system defaults

After the interface is completed, it is necessary to do the function, but wait, it seems not right, why the effect is much worse than cicada? The screenshot below shows the second version of Qingmang. Compared with the first version, the title of Window has been removed, but it still gives a feeling of being cramped and not concise enough. The color that I picked in the TableView doesn’t match the overall interface.

The second version of the Qing Mang prototype

The second version of the Qing Mang prototype

Why does this happen? Because up until now, we’ve used the system’s default options, with no designer aesthetic involved. How to give users a sense of personal customization? This requires us to override the default behavior and properties of the system, specifically, custom subclasses that inherit and override the parts of the parent class that do not meet the developer’s expectations.

From the end result, we need the entire software to look like a white background, so we specify the background color as white in every view loaded function

view.wantsLayer =true
self.view.layer? .backgroundColor=NSColor.white.cgColor
Copy the code

Although all view background colors are set to white, the close, Maximize, and minimize buttons are still on title, not overview. Set title to shadow, but they are missing again. The way to make them properly appear in Overview is to add:

self.window? .titleVisibility = .hiddenself.window? .titlebarAppearsTransparent =true
self.window? .styleMask.insert(.fullSizeContentView)Copy the code

There are two ways that you can do this with the background color of the selected state in TableView. The first is a custom NSTableCellView Cell coverage, coverage of the parent class override var backgroundStyle: NSBackgroundStyle {} properties. The second method is the issue that @jydemofork on Github sent me after my project, custom NSTableRowView, overrides the superclass method:

override func drawSelection(in dirtyRect:NSRect) {
    super.drawSelection(in: dirtyRect)
    var slectorRect =NSInsetRect(self.bounds,0.0)
    NSColor(calibratedWhite:0.92, alpha:1.0).setStroke()
    NSColor(calibratedWhite:0.92, alpha:1.0).setFill()
    var slectorPath =NSBezierPath(roundedRect: slectorRect, xRadius:0, yRadius:0)
    slectorPath.fill()
    slectorPath.stroke()
}
Copy the code

And then implement the tableView proxy method,

func tableView(_tableView:NSTableView, rowViewForRow row:Int) ->NSTableRowView? {
    let rowview = MyTableRowView(frame: .zero)
    return rowview
}
Copy the code

The separator bar between the two main views is thicker, which always makes people feel bad. The solution is to customize it. Override NSSplitView, override properties

override vardividerThickness:CGFloat{
    get {return0.5}}Copy the code

To disable this function, implement a proxy method for NSSplitView:

override func splitView(_ofDividerAtsplitView:NSSplitView, effectiveRect proposedEffectiveRect:NSRect, forDrawnRect drawnRect:NSRect, ofDividerAt dividerIndex:Int) ->NSRect{
    return NSRect.zero
}
Copy the code

After this chapter, it’s not hard to see that the code is still sound (😎). After the above adjustment, the interface looks simple, relaxed a lot, can be fake.

Hopefully, this chapter has taught you that in order to make something beautiful, you have to be bold enough to replace the system’s default options. This is usually done by overriding the properties and methods in the parent class, remembering to associate the component with the custom class.

Beautification of the interface

Beautification of the interface

A pit

In the process of customizing the TableView Cell, because the title of the article is usually quite long, it cannot be put down with NSTextField, so you must use NSTextView, and NSTextView can slide up and down by default, so when you slide up and down in the article list, Every time you slide into a TextView, the slide event will be captured by the white TextView, and the Scroll View in the TableView won’t have a chance to be captured.

And the way to do that is just like in the last video, by overwriting the Scroll view in the cell, overwriting the hitTest method

override func hitTest(_point:NSPoint) ->NSView? {
    return nil
}
Copy the code

Tell the cell that I’m not going to handle this sliding event, please hand it over to someone else.

NSTouchBar

To keep up with the trend, there are touchbars and notification centers built into the app. The TouchBar thing to watch out for is the linkage between NSWindow and NSViewController. From NSWindow to NSViewController:

let myViewcontroller =self.window? .contentViewControlleras! mainViewControllerCopy the code

The reverse process:

let mywindowController=NSApplication.shared().windows[0].windowControlleras? windowControllerCopy the code

In this way, when a button is pressed in the TouchBar, the effect of the selected button can be seen in the main screen, ensuring consistency.

Notification Center view

The notification center is pretty ugly, really just to try out the TodayExtension function. Imitating cicada, the current function only shows the list of articles on the home page. Click the article to open the original text with the default browser of the system. In fact, this is enough, after all, the notification center is to see a general use, who will not often open to see. Notification center is need to pay attention to the height of the custom views, by self. The preferredContentSize = CGSize (width: self. View. Frame. The size, width, height: XXX). The last thing to note is that using URLSession to request data prevents the UI from stalling, which makes the user feel bad.

func getData(with urlString:String,success:@escaping(Data?)->Void, failure: ((Error) - >Void)? =nil) {

         guard let url =URL(string: urlString)else{

         return

}
    let task =URLSession.shared.dataTask(with: url) { (data:Data? , response:URLResponse? , error:Error?).in
    DispatchQueue.main.async{
    if leterror = error { failure? (error) }else{
                      success(data)
                 }
          }
      }
     task.resume()
}
Copy the code

Article specific content view

In the API provided by qingmang team, there is a web-content item, which is wrapped by webView and loaded to display text and images, but there are some details that need to be taken into account. For example, some images are very large, although the window is limited to a value, but some images are much larger than this size. Web-content doesn’t have a title, so it looks awkward, and you have to add titles and headings manually. When the picture is too large, the window can slide around, how to limit him to slide. Font how to do with other parts of the view of the font does not conflict with the feeling, are the need to consider the problem, these can be controlled by the front-end CSS style, developers need to have a certain front-end experience. Because this public number center of gravity in fruit religion, so here is not specific to expand the narrative, interested friends can refer to my Github.

Green Awn propaganda

After finishing the work, CONSIDERING that the whole project was written with the latest SWIFT4, I @swiftLanguage on Weibo. The blogger is a medium V and most of his followers are interested in Swift or practitioners. In just two days, this microblog was read more than 10,000 times. Finally, I was delighted to find that Wang Junyu also gave this microblog a thumbs-up, thanking Jun Yu for his encouragement and affirmation.

Weibo screenshots

Weibo screenshots