Title bar
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
1A14FC2324D203D9009B3F83 /* TitlebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A14FC2224D203D9009B3F83 /* TitlebarView.swift */; };
|
||||||
1ADFF46024C7DE53006DC7AE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF45F24C7DE53006DC7AE /* AppDelegate.swift */; };
|
1ADFF46024C7DE53006DC7AE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF45F24C7DE53006DC7AE /* AppDelegate.swift */; };
|
||||||
1ADFF46224C7DE53006DC7AE /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF46124C7DE53006DC7AE /* SceneDelegate.swift */; };
|
1ADFF46224C7DE53006DC7AE /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF46124C7DE53006DC7AE /* SceneDelegate.swift */; };
|
||||||
1ADFF46924C7DE54006DC7AE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1ADFF46824C7DE54006DC7AE /* Assets.xcassets */; };
|
1ADFF46924C7DE54006DC7AE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1ADFF46824C7DE54006DC7AE /* Assets.xcassets */; };
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
1A14FC2224D203D9009B3F83 /* TitlebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitlebarView.swift; sourceTree = "<group>"; };
|
||||||
1ADFF45C24C7DE53006DC7AE /* SBrowser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SBrowser.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
1ADFF45C24C7DE53006DC7AE /* SBrowser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SBrowser.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
1ADFF45F24C7DE53006DC7AE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
1ADFF45F24C7DE53006DC7AE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
1ADFF46124C7DE53006DC7AE /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
1ADFF46124C7DE53006DC7AE /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
@@ -151,6 +153,7 @@
|
|||||||
children = (
|
children = (
|
||||||
1ADFF47324C7DE9C006DC7AE /* BrowserViewController.swift */,
|
1ADFF47324C7DE9C006DC7AE /* BrowserViewController.swift */,
|
||||||
1ADFF47824C7DFF8006DC7AE /* BrowserView.swift */,
|
1ADFF47824C7DFF8006DC7AE /* BrowserView.swift */,
|
||||||
|
1A14FC2224D203D9009B3F83 /* TitlebarView.swift */,
|
||||||
1ADFF4C824CA793E006DC7AE /* ToolbarViewController.swift */,
|
1ADFF4C824CA793E006DC7AE /* ToolbarViewController.swift */,
|
||||||
1ADFF4BF24CA6964006DC7AE /* URLBar.swift */,
|
1ADFF4BF24CA6964006DC7AE /* URLBar.swift */,
|
||||||
);
|
);
|
||||||
@@ -326,6 +329,7 @@
|
|||||||
1ADFF4C924CA793E006DC7AE /* ToolbarViewController.swift in Sources */,
|
1ADFF4C924CA793E006DC7AE /* ToolbarViewController.swift in Sources */,
|
||||||
1ADFF4CD24CBB0C8006DC7AE /* ScriptPolicyViewController.swift in Sources */,
|
1ADFF4CD24CBB0C8006DC7AE /* ScriptPolicyViewController.swift in Sources */,
|
||||||
1ADFF47924C7DFF8006DC7AE /* BrowserView.swift in Sources */,
|
1ADFF47924C7DFF8006DC7AE /* BrowserView.swift in Sources */,
|
||||||
|
1A14FC2324D203D9009B3F83 /* TitlebarView.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import WebKit
|
|||||||
|
|
||||||
class BrowserView: UIView
|
class BrowserView: UIView
|
||||||
{
|
{
|
||||||
|
let titlebarView = TitlebarView()
|
||||||
|
|
||||||
var toolbarView: ToolbarView? {
|
var toolbarView: ToolbarView? {
|
||||||
didSet { addSubview(toolbarView!) }
|
didSet { addSubview(toolbarView!) }
|
||||||
}
|
}
|
||||||
@@ -32,6 +34,8 @@ class BrowserView: UIView
|
|||||||
convenience init() {
|
convenience init() {
|
||||||
self.init(frame: .zero)
|
self.init(frame: .zero)
|
||||||
|
|
||||||
|
addSubview(titlebarView)
|
||||||
|
|
||||||
keyboardWillShowObserver = NotificationCenter.default.publisher(for: UIWindow.keyboardWillShowNotification).sink { notification in
|
keyboardWillShowObserver = NotificationCenter.default.publisher(for: UIWindow.keyboardWillShowNotification).sink { notification in
|
||||||
if let keyboardFrame = notification.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect {
|
if let keyboardFrame = notification.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect {
|
||||||
self.keyboardLayoutOffset = self.bounds.height - keyboardFrame.minY
|
self.keyboardLayoutOffset = self.bounds.height - keyboardFrame.minY
|
||||||
@@ -59,5 +63,21 @@ class BrowserView: UIView
|
|||||||
toolbarView.bounds = CGRect(origin: .zero, size: toolbarSize)
|
toolbarView.bounds = CGRect(origin: .zero, size: toolbarSize)
|
||||||
toolbarView.center = CGPoint(x: bounds.center.x, y: bounds.maxY - (toolbarView.bounds.height / 2) - keyboardLayoutOffset)
|
toolbarView.center = CGPoint(x: bounds.center.x, y: bounds.maxY - (toolbarView.bounds.height / 2) - keyboardLayoutOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bringSubviewToFront(titlebarView)
|
||||||
|
|
||||||
|
var titlebarHeight: CGFloat = 24.0
|
||||||
|
titlebarHeight += safeAreaInsets.top
|
||||||
|
|
||||||
|
titlebarView.frame = CGRect(origin: .zero, size: CGSize(width: bounds.width, height: titlebarHeight))
|
||||||
|
|
||||||
|
// Fix web view content insets
|
||||||
|
webView?.scrollView.automaticallyAdjustsScrollIndicatorInsets = false
|
||||||
|
|
||||||
|
var webViewContentInset = UIEdgeInsets()
|
||||||
|
webViewContentInset.top = titlebarView.frame.height
|
||||||
|
webViewContentInset.bottom = toolbarView?.frame.height ?? 0
|
||||||
|
webView?.scrollView.contentInset = webViewContentInset
|
||||||
|
webView?.scrollView.scrollIndicatorInsets = webViewContentInset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,11 @@ class BrowserViewController: UIViewController,
|
|||||||
private var blockedScriptOrigins = Set<String>()
|
private var blockedScriptOrigins = Set<String>()
|
||||||
override var canBecomeFirstResponder: Bool { true }
|
override var canBecomeFirstResponder: Bool { true }
|
||||||
|
|
||||||
|
private var titleObservation: NSKeyValueObservation?
|
||||||
private var loadingObservation: NSKeyValueObservation?
|
private var loadingObservation: NSKeyValueObservation?
|
||||||
|
|
||||||
|
override var preferredStatusBarStyle: UIStatusBarStyle { .lightContent }
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
}
|
}
|
||||||
@@ -64,6 +67,11 @@ class BrowserViewController: UIViewController,
|
|||||||
self.toolbarController.urlBar.loadProgress = .loading(progress: webView.estimatedProgress)
|
self.toolbarController.urlBar.loadProgress = .loading(progress: webView.estimatedProgress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Title observer
|
||||||
|
titleObservation = webView.observe(\.title, changeHandler: { (webView, observedChange) in
|
||||||
|
self.browserView.titlebarView.titleLabelView.text = webView.title
|
||||||
|
})
|
||||||
|
|
||||||
self.view = browserView
|
self.view = browserView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
60
SBrowser/Browser View/TitlebarView.swift
Normal file
60
SBrowser/Browser View/TitlebarView.swift
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
//
|
||||||
|
// TitlebarView.swift
|
||||||
|
// SBrowser
|
||||||
|
//
|
||||||
|
// Created by James Magahern on 7/29/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class TitlebarView: UIView
|
||||||
|
{
|
||||||
|
public let titleLabelView = UILabel(frame: .zero)
|
||||||
|
private let backgroundImageView = UIImageView(frame: .zero)
|
||||||
|
|
||||||
|
convenience init() {
|
||||||
|
self.init(frame: .zero)
|
||||||
|
addSubview(backgroundImageView)
|
||||||
|
addSubview(titleLabelView)
|
||||||
|
|
||||||
|
titleLabelView.textColor = .white
|
||||||
|
titleLabelView.layer.shadowColor = UIColor.black.cgColor
|
||||||
|
titleLabelView.layer.shadowRadius = 0.0
|
||||||
|
titleLabelView.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
|
||||||
|
titleLabelView.font = UIFont.boldSystemFont(ofSize: 12.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func backgroundImageForSize(_ size: CGSize) -> UIImage? {
|
||||||
|
var image: UIImage? = nil
|
||||||
|
|
||||||
|
UIGraphicsBeginImageContext(CGSize(width: size.width, height: 1.0))
|
||||||
|
if let context = UIGraphicsGetCurrentContext() {
|
||||||
|
let gradientColorsArray = [
|
||||||
|
UIColor(red: 0.101, green: 0.176, blue: 0.415, alpha: 1.0).cgColor,
|
||||||
|
UIColor(red: 0.153, green: 0.000, blue: 0.153, alpha: 1.0).cgColor
|
||||||
|
]
|
||||||
|
|
||||||
|
if let gradient = CGGradient(colorsSpace: nil, colors: gradientColorsArray as CFArray, locations: nil) {
|
||||||
|
context.drawLinearGradient(gradient, start: .zero, end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
|
||||||
|
}
|
||||||
|
|
||||||
|
image = UIGraphicsGetImageFromCurrentImageContext()
|
||||||
|
UIGraphicsEndImageContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
|
||||||
|
override func layoutSubviews() {
|
||||||
|
super.layoutSubviews()
|
||||||
|
|
||||||
|
backgroundImageView.frame = bounds
|
||||||
|
titleLabelView.frame = bounds.avoiding(verticalInsets: safeAreaInsets).insetBy(dx: 8.0, dy: 0.0)
|
||||||
|
|
||||||
|
if let image = backgroundImageView.image, image.size == bounds.size {
|
||||||
|
// No op
|
||||||
|
} else {
|
||||||
|
backgroundImageView.image = backgroundImageForSize(bounds.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ class URLBar: UIView
|
|||||||
textField.keyboardType = .webSearch
|
textField.keyboardType = .webSearch
|
||||||
textField.autocorrectionType = .no
|
textField.autocorrectionType = .no
|
||||||
textField.autocapitalizationType = .none
|
textField.autocapitalizationType = .none
|
||||||
textField.font = .preferredFont(forTextStyle: .body)
|
textField.font = .systemFont(ofSize: 14.0)
|
||||||
textField.clearingBehavior = .clearOnInsertionAndShowSelectionTint
|
textField.clearingBehavior = .clearOnInsertionAndShowSelectionTint
|
||||||
addSubview(textField)
|
addSubview(textField)
|
||||||
|
|
||||||
|
|||||||
@@ -14,4 +14,12 @@ extension CGRect
|
|||||||
return CGPoint(x: size.width / 2.0, y: size.height / 2.0)
|
return CGPoint(x: size.width / 2.0, y: size.height / 2.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func avoiding(verticalInsets insets: UIEdgeInsets) -> CGRect {
|
||||||
|
var rect = self
|
||||||
|
rect.origin.y += insets.top
|
||||||
|
rect.size.height -= insets.top
|
||||||
|
|
||||||
|
return rect
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user