largeTitle of navigationBar collapse after refreshControl.endRefreshing swift - ios

Encountered a problem: largeTitle of navigation bar collapsing to small title ~once per 20 attempts after refreshControl.endRefreshing().
tableView is first subview of subviews hierarchy, and top constraint is to superview (not to safeArea)
refreshControl added to tableView.refreshControl, not as subview of tableView
was trying call navigationBar.sizeToFit() after endRefreshing - not success.
Controller code:
override public func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true
title = L10n.Trainers.trainers.uppercased()
navigationController?.navigationBar.layoutMargins = .init(top: 0, left: 16, bottom: 0, right: 16)
configureSubviews()
makeConstraints()
configureBindings()
configureActions()
setupTableView()
setupResultsTableView()
}
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.sizeToFit()
}
override public func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
navigationController?.navigationItem.largeTitleDisplayMode = .automatic
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
vm.onViewDidAppear()
mainView.tableView.refreshControl = mainView.refreshControl
}
override public func loadView() {
view = mainView
}
Refresh-logic code:
vm.isLoading.drive { [weak self] loading in
guard let self = self else { return }
if self.mainView.refreshControl.isRefreshing {
if !loading {
self.mainView.tableView.refreshControl?.endRefreshing()
}
} else {
if loading {
var style = LoaderParameters.blue
style.installConstraints = false
self.mainView.tableView.startLoading(with: style)
self.mainView.tableView.existedLoaderView?.centerX().centerY(-40)
} else {
self.mainView.tableView.stopLoadingProgress()
}
}
}.store(in: &subscriptions)
View code:
final class TrainersView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
configureSubviews()
makeConstraints()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private(set) lazy var refreshControl = UIRefreshControl().configureWithAutoLayout {
$0.tintColor = Asset.mainGrey.color
}
private(set) lazy var topView: UIView = {
let view = UIView()
view.backgroundColor = .clear
return view
}()
private(set) lazy var tableView = UITableView().configureWithAutoLayout {
$0.register(TrainerCell.self)
$0.tableFooterView = UIView()
$0.showsVerticalScrollIndicator = false
$0.separatorStyle = .none
$0.backgroundColor = Asset.mainWhite.color
}
private func configureSubviews() {
addSubview(tableView)
topView.addSubview(segmentedControl)
tableView.tableHeaderView = topView
tableView.tableHeaderView?.frame.size.height = 60
tableView.tableFooterView?.frame.size.height = 40
tableView.reloadData()
}
private func makeConstraints() {
tableView.pinToSuperview()
segmentedControl.centerX()
segmentedControl.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: -8).priority(999).activate()
segmentedControl.widthAnchor ~ widthAnchor - 16 * 2
}
}

Related

Scroll the ScrollView when tap a button Swift with ViewCode

I'm creating a ViewPager in Swift using ViewCode.
I need to create the following action: tap on the Next button (method: actionNextPressed() ), and scroll the scrollview to the next page (like a TapGesture scrolling to right or left).
Here is my Swift code, what I've tried until now, and the printscreen from the viewpager (at the moment)
PagerViewController.swift
import UIKit
import SnapKit
open class PagerViewController: UIViewController, UIPageViewControllerDelegate {
private lazy var dimmedView: UIView = {
let view = UIView()
view.backgroundColor = .black
view.alpha = maxDimmedAlpha
return view
}()
private lazy var containerView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 1, alpha: 0)
return view
}()
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.showsHorizontalScrollIndicator = false
scrollView.isPagingEnabled = true
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(pages.count), height: containerView.frame.height)
for i in 0..<pages.count {
var page = pages[i]
let dialog = PageViewController(
icon: page.icon,
titleText: page.title,
descriptionText: page.description,
titleActionButton: page.titleButton,
actionButton: page.actionButton
)!
scrollView.addSubview(dialog.view)
scrollView.subviews[i].frame = CGRect(
x: view.frame.width * CGFloat(i),
y: 0,
width: containerView.frame.width,
height: containerView.frame.height
)
}
scrollView.delegate = self
return scrollView
}()
lazy var pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.currentPage = 0
pageControl.numberOfPages = pages.count
pageControl.addTarget(self, action: #selector(pageControlTapHandler(sender:)), for: .allEvents)
pageControl.isUserInteractionEnabled = false
pageControl.pageIndicatorTintColor = .systemGray
pageControl.currentPageIndicatorTintColor = .systemBlue
pageControl.backgroundColor = .white
return pageControl
}()
private lazy var directionsButtonsStackView: UIStackView = {
let view = UIStackView()
view.axis = .horizontal
view.distribution = .fillEqually
view.backgroundColor = .red
return view
}()
private lazy var buttonJump = UIButton()
private lazy var buttonBefore = UIButton()
private lazy var buttonNext = UIButton()
private var titleJumpButton: String! = ""
private let maxDimmedAlpha: CGFloat = 0.6
open var pages: Array<PageModel>!
private var currentPage: Int = 0
init?(listPages: Array<PageModel>, titleJumpButton: String) {
super.init(nibName: nil, bundle: nil)
self.pages = listPages
self.titleJumpButton = titleJumpButton
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc func pageControlTapHandler(sender: UIPageControl) {
scrollView.scrollTo(horizontalPage: sender.currentPage)
}
open override func viewDidLoad() {
super.viewDidLoad()
setupView()
addViewComponents()
setupConstraints()
}
private func setupView() {
self.buttonJump = PageButton(frame: .zero).build(
context: self,
title: titleJumpButton!,
selector: #selector(actionJumpPressed)
)
self.buttonBefore = PageButton(frame: .zero).build(
context: self,
title: "Before",
selector: #selector(actionBeforePressed)
)
self.buttonBefore.backgroundColor = .white
self.buttonNext = PageButton(frame: .zero).build(
context: self,
title: "Next",
selector: #selector(actionNextPressed)
)
self.buttonJump.setTitle(titleJumpButton, for: .normal)
}
private func addViewComponents() {
view.addSubview(dimmedView)
containerView.addSubview(scrollView)
containerView.addSubview(pageControl)
directionsButtonsStackView.addArrangedSubview(buttonBefore)
directionsButtonsStackView.addArrangedSubview(buttonNext)
containerView.addSubview(directionsButtonsStackView)
containerView.addSubview(buttonJump)
view.addSubview(containerView)
}
private func setupConstraints() {
dimmedView.snp.makeConstraints { make in
make.top.equalToSuperview()
make.bottom.equalToSuperview()
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
}
containerView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(100)
make.bottom.equalToSuperview().inset(100)
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.centerX.equalToSuperview()
make.centerY.equalToSuperview()
make.margins.equalTo(20)
}
scrollView.snp.makeConstraints { make in
make.top.equalToSuperview()
make.bottom.equalTo(pageControl.snp.top)
make.leading.equalTo(containerView.snp.leading)
make.trailing.equalTo(containerView.snp.trailing)
}
pageControl.snp.makeConstraints { make in
make.bottom.equalTo(directionsButtonsStackView.snp.top)
make.leading.equalTo(containerView.snp.leading).offset(20)
make.trailing.equalTo(containerView.snp.trailing).inset(20)
make.height.equalTo(30)
make.centerX.equalToSuperview()
}
directionsButtonsStackView.snp.makeConstraints { make in
make.bottom.equalTo(buttonJump.snp.top)
make.leading.equalTo(containerView.snp.leading).offset(20)
make.trailing.equalTo(containerView.snp.trailing).inset(20)
make.height.equalTo(60)
make.width.greaterThanOrEqualTo(0)
make.centerX.equalToSuperview()
}
buttonJump.snp.makeConstraints { make in
make.bottom.equalToSuperview().inset(10)
make.leading.equalTo(containerView).offset(20)
make.trailing.equalTo(containerView).inset(20)
make.centerX.equalToSuperview()
make.width.greaterThanOrEqualTo(0)
make.height.equalTo(50)
}
}
#objc private func actionJumpPressed() {
self.dismiss(animated: true, completion: nil)
}
#objc private func actionBeforePressed() {
if currentPage == 0 {
return
} else {
currentPage -= 1
pageControl.currentPage = currentPage
}
}
#objc private func actionNextPressed() {
if currentPage == pages.count {
return
} else {
currentPage += 1
pageControl.currentPage = currentPage
}
}
}
extension PagerViewController: UIScrollViewDelegate {
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = Int(round(scrollView.contentOffset.x / view.frame.width))
pageControl.currentPage = pageIndex
currentPage = pageIndex
}
}
extension UIScrollView {
func scrollTo(horizontalPage: Int? = 0) {
var frame: CGRect = self.frame
frame.origin.x = frame.size.width * CGFloat(horizontalPage ?? 0)
self.scrollRectToVisible(frame, animated: true)
}
}
I had the same issue once with a collectionView. You have to turn off the .isPagingEnabled, scroll the scrollview where you want and turn it back on the paging.
func scrollTo(horizontalPage: Int? = 0) {
scrollView.isPagingEnabled = false
var frame: CGRect = self.frame
frame.origin.x = frame.size.width * CGFloat(horizontalPage ?? 0)
self.scrollRectToVisible(frame, animated: true)
scrollView.isPagingEnabled = true
}

InputAccessoryView bug when dismiss controller and return ago

Who can help me? I create chat controller via UITableViewController, UINavigationController and I use InputAccessoryView. If I swipe screen to left (dismiss this controller) and return swipe to right (cancel dismiss) - table set adjustContentInset bottom to zero and InputAcessoryView close bottom content tableView. This problem created in ViewWillAppear event. My code:
UITableViewController:
// MARK: - Controller data
lazy var inputContainerView = ChatAccessoryView(frame: .zero, buttonSelector: #selector(sendMessage(sender:)), controller: self)
public var ticketID: Int = 0
private var lastMessageID: Int = 0
private var tableSections: [String] = []
private var tableRows: [[SupportTicketMessage]] = []
private var sendingMessage: Bool = false
private var URLTaskGetMessages: URLSessionDataTask?
private var URLTaskSendMessage: URLSessionDataTask?
// MARK: - Controller overrides
override func loadView() {
super.loadView()
tableView.register(ChatHeaderView.self, forHeaderFooterViewReuseIdentifier: "chatHeader")
tableView.register(ChatFromMessageTableViewCell.self, forCellReuseIdentifier: "chatFromMessage")
tableView.register(ChatToMessageTableViewCell.self, forCellReuseIdentifier: "chatToMessage")
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
if let messages = supportClass.getTicketMessages(ticketID) {
tableSections = messages.sections
tableRows = messages.rows
lastMessageID = messages.lastMessage
scrollTableToBottom(false)
} else {
tableView.setLoaderBackground("Загрузка сообщений...")
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
loadMessages()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
URLTaskGetMessages?.cancel()
URLTaskSendMessage?.cancel()
}
override var inputAccessoryView: UIView? {
return inputContainerView
}
override var canBecomeFirstResponder: Bool {
return true
}
ChatAccessoryView:
class ChatAccessoryView: UIView {
// MARK: - Get params to init
let buttonSelector: Selector
let controller: UIViewController
// MARK: - Data
private let textView = ChatTextView()
private let sendButton = LoadingButton(frame: .zero, text: "Отпр.")
private let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .extraLight))
// MARK: - Init
required init(frame: CGRect, buttonSelector: Selector, controller: UIViewController) {
self.buttonSelector = buttonSelector
self.controller = controller
super.init(frame: frame)
configureContents()
blurEffectConfigure()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Overrides
override var intrinsicContentSize: CGSize {
return .zero
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
blurEffectConfigure()
}
override func didMoveToWindow() {
super.didMoveToWindow()
if let window = window {
textView.bottomAnchor.constraint(lessThanOrEqualToSystemSpacingBelow: window.safeAreaLayoutGuide.bottomAnchor, multiplier: 1.0).isActive = true
}
}
// MARK: - Private methods
private func configureContents() {
backgroundColor = .clear
autoresizingMask = .flexibleHeight
textView.placeholder = "Напишите сообщение..."
textView.maxHeight = 160
textView.font = .systemFont(ofSize: 17)
textView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
textView.layer.cornerRadius = 8
textView.textContainerInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 4)
sendButton.titleLabel?.font = .boldSystemFont(ofSize: 17)
sendButton.setTitleColor(controller.view.tintColor, for: .normal)
sendButton.addTarget(controller, action: buttonSelector, for: .touchUpInside)
blurView.translatesAutoresizingMaskIntoConstraints = false
textView.translatesAutoresizingMaskIntoConstraints = false
sendButton.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(blurView)
self.addSubview(textView)
self.addSubview(sendButton)
blurView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
blurView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
blurView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blurView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
textView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20).isActive = true
textView.topAnchor.constraint(equalTo: self.topAnchor, constant: 8).isActive = true
textView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8 ).isActive = true
textView.trailingAnchor.constraint(equalTo: sendButton.leadingAnchor, constant: -20).isActive = true
sendButton.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
sendButton.widthAnchor.constraint(equalToConstant: 48).isActive = true
sendButton.centerYAnchor.constraint(equalTo: textView.centerYAnchor).isActive = true
}
private func blurEffectConfigure() {
if #available(iOS 13.0, *) {
if traitCollection.userInterfaceStyle == .light {
blurView.effect = UIBlurEffect(style: .extraLight)
} else {
blurView.effect = UIBlurEffect(style: .dark)
}
}
}
// MARK: - Public methods
public func successSend() {
textView.text = ""
sendButton.loadingMode(false)
}
}
ChatTextView:
class ChatTextView: UITextView {
// MARK: - Data
var maxHeight: CGFloat = 0.0
public let placeholderTextView: UITextView = {
let textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.backgroundColor = .clear
textView.isScrollEnabled = false
textView.isUserInteractionEnabled = false
textView.textColor = UIColor.black.withAlphaComponent(0.33)
return textView
}()
var placeholder: String? {
get {
return placeholderTextView.text
}
set {
placeholderTextView.text = newValue
}
}
// MARK: - Init
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
backgroundColor = UIColor.black.withAlphaComponent(0.06)
isScrollEnabled = false
autoresizingMask = [.flexibleWidth, .flexibleHeight]
NotificationCenter.default.addObserver(self, selector: #selector(UITextInputDelegate.textDidChange(_:)), name: UITextView.textDidChangeNotification, object: self)
placeholderTextView.font = font
addSubview(placeholderTextView)
NSLayoutConstraint.activate([
placeholderTextView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8),
placeholderTextView.trailingAnchor.constraint(equalTo: trailingAnchor),
placeholderTextView.topAnchor.constraint(equalTo: topAnchor),
placeholderTextView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
colorThemeConfigure()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Overrides
override var text: String! {
didSet {
invalidateIntrinsicContentSize()
placeholderTextView.isHidden = !text.isEmpty
}
}
override var font: UIFont? {
didSet {
placeholderTextView.font = font
invalidateIntrinsicContentSize()
}
}
override var contentInset: UIEdgeInsets {
didSet {
placeholderTextView.contentInset = contentInset
}
}
override var intrinsicContentSize: CGSize {
var size = super.intrinsicContentSize
if size.height == UIView.noIntrinsicMetric {
layoutManager.glyphRange(for: textContainer)
size.height = layoutManager.usedRect(for: textContainer).height + textContainerInset.top + textContainerInset.bottom
}
if maxHeight > 0.0 && size.height > maxHeight {
size.height = maxHeight
if !isScrollEnabled {
isScrollEnabled = true
}
} else if isScrollEnabled {
isScrollEnabled = false
}
return size
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
colorThemeConfigure()
}
// MARK: - Private methods
private func colorThemeConfigure() {
if #available(iOS 13.0, *) {
if traitCollection.userInterfaceStyle == .light {
backgroundColor = UIColor.black.withAlphaComponent(0.06)
placeholderTextView.textColor = UIColor.black.withAlphaComponent(0.33)
} else {
backgroundColor = UIColor.white.withAlphaComponent(0.08)
placeholderTextView.textColor = UIColor.white.withAlphaComponent(0.33)
}
}
}
// MARK: - Obj C methods
#objc private func textDidChange(_ note: Notification) {
invalidateIntrinsicContentSize()
placeholderTextView.isHidden = !text.isEmpty
}
}
Screenshots error:
TableView loaded (all right)
Swipe screen to left and cancel this action (swipe right)
When I returned to controller I see this Bug (last message go to bottom)
Thanks!
You could try something like this:
UITableViewController:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
updateTableViewInsets()
}
private func updateTableViewInsets() {
let offSet = inputContainerView.frame.height
tableView?.contentInset.bottom = offSet
tableView?.scrollIndicatorInsets.bottom = offSet
}
Thank you all for your attention and trying to help me! I solved the problem as follows:
tableView.contentInsetAdjustmentBehavior = .never
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 53, right: 0)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
I disable automatic tableView.contentInsetAdjustmentBehavior and use tableView.conentInset. On open/close keyboard I change tableView.contentInset.
This works well for me, and pretty simple solution:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
reloadInputViews()
prepareTableViewForViewPresented()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
prepareTableViewForViewDismissed()
}
private func prepareTableViewForViewPresented() {
self.tableView.contentInset.bottom = 0
}
private func prepareTableViewForViewDismissed() {
self.tableView.contentInset.bottom = view.safeAreaInsets.bottom + (inputAccessoryView?.frame.height ?? 0)
}
Known issues:
- when keyboard is shown, tableview still goes behind keyboard

Select and deselect reusable views

I create a custom view in xib file. I add 3 views(which inherited from custom) in viewController. Initially they have white color, but when i click on first view it should be changed other color and if i click on second view, the first view should be back in white color.
I need help to change first view color back to white when second view is selected.
My code for customView here
class SubscriptionView: UIView {
#IBOutlet weak var title: UILabel!
#IBOutlet weak var subTitle: UILabel!
#IBOutlet weak var checkMark: UIImageView!
var isSelect: Bool = false
let nibName = "SubscriptionView"
var contentView: UIView?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
override func awakeFromNib() {
super.awakeFromNib()
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapAction)))
}
func commonInit() {
guard let view = loadViewFromNib() else {
return
}
view.frame = self.bounds
view.layer.masksToBounds = true
view.layer.cornerRadius = 14
view.layerBorderColor = AppColor.amaranth
view.layerBorderWidth = 0.5
self.addSubview(view)
contentView = view
}
func loadViewFromNib() -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nibName, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
public func selectedView(_ isSelect: Bool) {
self.isSelect = isSelect
title.textColor = isSelect ? UIColor.white : AppColor.amaranth
subTitle.textColor = isSelect ? UIColor.white : AppColor.amaranth
checkMark.alpha = isSelect ? 1.0 : 0.0
contentView!.backgroundColor = isSelect ? AppColor.amaranth : UIColor.white
}
#objc private func tapAction() {
///????? selectedView
}
}
Here is a very simple example using the Delegate / Protocol pattern.
Define a Protocol:
// Protocol / Delegate pattern
protocol SubscriptionViewDelegate {
func gotTap(from sender: SubscriptionView)
}
Have your view controller conform to that protocol. In your custom SubscriptionView class, when the user taps you will tell the delegate that a tap was received, and the controller will loop through the SubscriptionView objects setting the "selected" state to true or false, based on the tapped view.
class SubscriptionsViewController: UIViewController, SubscriptionViewDelegate {
let theStackView: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.alignment = .fill
v.distribution = .fill
v.spacing = 20
return v
}()
// array to track the "subscription" views
var arrayOfSubscriptionViews: [SubscriptionView] = [SubscriptionView]()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
// add a stack view to hold the "subscription" views
view.addSubview(theStackView)
NSLayoutConstraint.activate([
theStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20.0),
theStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20.0),
theStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20.0),
])
// instantiate 3 "subscription" views
for _ in 1...3 {
// instantiate view
let v = SubscriptionView()
// set self as its delegate
v.delegate = self
// add it to our stack view
theStackView.addArrangedSubview(v)
// append it to our tracking array
arrayOfSubscriptionViews.append(v)
}
}
func gotTap(from sender: SubscriptionView) {
// just for dev / debugging
print("got tap from", sender)
// loop through the subscription views,
// setting the sender selected to TRUE
// the others to FALSE
arrayOfSubscriptionViews.forEach {
$0.selectedView($0 == sender)
}
}
}
// Protocol / Delegate pattern
protocol SubscriptionViewDelegate {
func gotTap(from sender: SubscriptionView)
}
class SubscriptionView: UIView {
#IBOutlet weak var title: UILabel!
#IBOutlet weak var subTitle: UILabel!
#IBOutlet weak var checkMark: UIImageView!
var isSelect: Bool = false
var delegate: SubscriptionViewDelegate?
let nibName = "SubscriptionView"
var contentView: UIView?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
override func awakeFromNib() {
super.awakeFromNib()
}
func commonInit() {
guard let view = loadViewFromNib() else {
return
}
view.frame = self.bounds
view.layer.masksToBounds = true
view.layer.cornerRadius = 14
view.layer.borderColor = UIColor.red.cgColor // AppColor.amaranth
view.layer.borderWidth = 0.5
self.addSubview(view)
contentView = view
selectedView(false)
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapAction)))
}
func loadViewFromNib() -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nibName, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
public func selectedView(_ isSelect: Bool) {
self.isSelect = isSelect
title.textColor = isSelect ? UIColor.white : .red // AppColor.amaranth
subTitle.textColor = isSelect ? UIColor.white : .red // AppColor.amaranth
checkMark.alpha = isSelect ? 1.0 : 0.0
// contentView!.backgroundColor = isSelect ? AppColor.amaranth : UIColor.white
contentView!.backgroundColor = isSelect ? UIColor.red : UIColor.white
}
#objc private func tapAction() {
// for dev / debugging
print("sending tap from", self)
// tell the delegate self got tapped
delegate?.gotTap(from: self)
}
}
I only made minor changes to your SubscriptionView class, so you should be able to use it as-is with your existing .xib

UISearchBar's text move to bottom when input content?

I customized a UISearchbar, the code is like this:
class CustomSearchBar: UIView {
lazy var searchBar: MySearchBar = {
let search = MySearchBar()
search.tintColor = UIColor.orange
search.barTintColor = UIColor.yellow
search.searchBarStyle = .minimal
search.searchTextPositionAdjustment = UIOffset(horizontal: 10, vertical: 0)
return search
}()
lazy var cancelButton: UIButton = {
let button = UIButton(type: .custom)
button.setTitle("取消", for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
setupConstraints()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
addSubview(searchBar)
addSubview(cancelButton)
}
private func setupConstraints() {
searchBar.snp.makeConstraints { (make) in
make.left.equalToSuperview().offset(20)
make.top.equalToSuperview().offset(6)
make.height.equalTo(32)
make.width.equalToSuperview().offset(-80)
}
cancelButton.snp.makeConstraints { (make) in
make.left.equalTo(searchBar.snp.right).offset(13)
make.centerY.equalTo(searchBar)
}
}
}
class MySearchBar: UISearchBar {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func indexOfSearchFieldInSubviews() -> Int! {
var index: Int!
let searchBarView = subviews[0]
for (i, view) in searchBarView.subviews.enumerated() {
if view.isKind(of: UITextField.self) {
index = i
break
}
}
return index
}
override func draw(_ rect: CGRect) {
if let index = indexOfSearchFieldInSubviews() {
let searchField: UITextField = subviews[0].subviews[index] as! UITextField
searchField.leftView = UIImageView(image: UIImage(named: "Search_icon"))
searchField.font = UIFont.systemFont(ofSize: 14)
searchField.borderStyle = .none
searchField.layer.masksToBounds = true
searchField.layer.cornerRadius = 4
searchField.backgroundColor = barTintColor
searchField.contentVerticalAlignment = .center
searchField.placeholder = "input something"
}
}
}
we can see that it is very simple. Just added a searchBar and cancelButton.
Then I added it to navigationBar as subView, make it becomeFirstResponder in viewController.
class ViewController: UIViewController {
lazy var customeSearchBar = CustomSearchBar()
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.addSubview(customeSearchBar)
customeSearchBar.snp.makeConstraints { (make) in
make.left.right.equalToSuperview()
make.centerY.equalToSuperview()
make.height.equalTo(44)
}
customeSearchBar.searchBar.becomeFirstResponder()
}
}
At first, I input content is ok.
When I continue input content, then the issue shows up:
It looks like the content move to the bottom. I tried to find something to fix the problem. But I didn't get it.
It is a strange thing that works fine in simulate and some iPhone. But one of my phone works wrong.

Failed that ImageView in scrollView zoom in by swift3

Sorry I am new to swift and I have an imageView.
I can see my image in imageView.
I want to be able to zoom the image in and out. But I also fail to change my image size. What's wrong with my code? Sorry,I already find many solution to fix my problem. I don't know how to fix it. Should I add some gestureRecognizer or anything else?
Thank for answer.
This is code:
import UIKit
import SnapKit
class ImageViewController: UIViewController, UIScrollViewDelegate {
var url:String = ""
var id:String = ""
var scrollView:UIScrollView = { () -> UIScrollView in
let ui = UIScrollView()
ui.backgroundColor = UIColor.black
ui.minimumZoomScale = 1.0
ui.maximumZoomScale = 6.0
return ui
}()
var toolbar:UIToolbar = { () -> UIToolbar in
let ui = UIToolbar()
ui.barTintColor = defaultNavBackgroundColor
ui.clipsToBounds = true
ui.isTranslucent = false
ui.isUserInteractionEnabled = true
return ui
}()
var photoImageView:UIImageView = { () -> UIImageView in
let ui = UIImageView()
ui.backgroundColor = UIColor.clear
ui.layer.masksToBounds = true
ui.contentMode = .scaleAspectFit
ui.isUserInteractionEnabled = true
return ui
}()
var buttonDownload:UIBarButtonItem = { () -> UIBarButtonItem in
let ui = UIBarButtonItem()
ui.style = .plain
return ui
}()
override func loadView() {
super.loadView()
view.backgroundColor = UIColor.black
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
// navigationItem.title = name
self.automaticallyAdjustsScrollViewInsets = false
imageFromUrl(imageView: photoImageView, url: url, chatroomId: id,isResize: false)
self.buttonDownload.action = #selector(btnDownloadClicked(sender:))
scrollView.delegate = self
scrollView.contentSize = (self.photoImageView.image!.size)
photoImageView.center = scrollView.center
loadContent()
loadVFL()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func loadContent() {
toolbar.sizeToFit()
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
buttonDownload = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: nil)
toolbar.items = [flexSpace,buttonDownload]
view.addSubview(scrollView)
view.addSubview(toolbar)
scrollView.addSubview(photoImageView)
}
func loadVFL() {
scrollView.snp.makeConstraints { (make) -> Void in
make.top.equalToSuperview()
make.bottom.equalTo(toolbar.snp.top)
make.left.equalToSuperview()
make.right.equalToSuperview()
}
photoImageView.snp.makeConstraints { (make) -> Void in
make.top.equalToSuperview()
make.bottom.equalToSuperview()
make.left.equalToSuperview()
make.right.equalToSuperview()
make.centerX.equalToSuperview()
make.centerY.equalToSuperview()
}
toolbar.snp.makeConstraints { (make) -> Void in
make.width.equalToSuperview()
make.bottom.equalToSuperview()
make.height.equalTo(44)
}
}
func btnDownloadClicked(sender:UIBarButtonItem) {
print("press")
}
// MARK: - UIScrollViewDelegate
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return photoImageView
}
}
image like this

Resources