自定义分段控件不切换视图
Custom Segmented Control Not Switching Views
我做了一个自定义的 UIControl:
import UIKit
@IBDesignable class FeedViewSC: UIControl {
fileprivate var labels = [UILabel]()
var thumbView = UIView()
var items: [String] = ["Tab1", "Tab2"] {
didSet {
setupLabels()
}
}
var selectedIndex : Int = 0 {
didSet{
displayNewSelectedIndex()
}
}
@IBInspectable var font : UIFont! = UIFont.systemFont(ofSize: 13) {
didSet {
setFont()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
func setupView() {
layer.cornerRadius = 5
layer.borderColor = UIColor(red: 239/255, green: 239/255, blue: 239/255, alpha: 1).cgColor
layer.borderWidth = 2
backgroundColor = UIColor(red: 239/255, green: 239/255, blue: 239/255, alpha: 1)
setupLabels()
insertSubview(thumbView, at: 0)
}
func setupLabels() {
for label in labels {
label.removeFromSuperview()
}
labels.removeAll(keepingCapacity: true)
for index in 1...items.count {
let label = UILabel(frame: CGRect.zero)
label.text = items[index-1]
label.textAlignment = .center
label.font = UIFont(name: "Nunito",size: 17)
label.textColor = UIColor(red: 51/255, green: 51/255, blue: 51/255, alpha: 1)
self.addSubview(label)
labels.append(label)
}
}
override func layoutSubviews() {
super.layoutSubviews()
var selectFrame = self.bounds
let newWidth = selectFrame.width / CGFloat(items.count)
selectFrame.size.width = newWidth
thumbView.frame = selectFrame
thumbView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1)
thumbView.layer.cornerRadius = 5
let labelHeight = self.bounds.height
let labelWidth = self.bounds.width / CGFloat(labels.count)
for index in 0...labels.count - 1 {
let label = labels[index]
let xPosition = CGFloat(index) * labelWidth
label.frame = CGRect(x: xPosition, y: 0, width: labelWidth, height: labelHeight)
}
}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
let location = touch.location(in: self)
var calculatedIndex: Int?
for (index, item) in labels.enumerated() {
if item.frame.contains(location){
calculatedIndex = index
}
}
if calculatedIndex != nil {
selectedIndex = calculatedIndex!
sendActions(for: .valueChanged)
}
return false
}
func displayNewSelectedIndex (){
if(self.selectedIndex == -1){
self.selectedIndex = self.items.count-1
}
let label = labels[selectedIndex]
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 0.90, initialSpringVelocity: 0.8, options: [], animations: {
self.thumbView.frame = label.frame
}, completion: nil)
}
func setFont(){
for item in labels {
item.font = font
}
}
}
我将它嵌入到我的 ViewController 中并尝试让它以编程方式在两个视图之间切换:
import UIKit
class FeedViewController: UIViewController {
let feedViewSC = FeedViewSC()
let firstView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let secondView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.blue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let (width, height) = UIScreen.main.bounds.wh
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
view.addSubview(firstView)
view.addSubview(secondView)
setupContainerViews()
firstView.isHidden = false
secondView.isHidden = true
myTravel.selectedIndex = 0
let feedControl = FeedViewSC(frame: CGRect(x: 65, y: 5, width: width-130, height: 35))
feedControl.autoresizingMask = [.flexibleWidth,.flexibleHeight]
self.navigationController?.navigationBar.addSubview(feedControl)
feedControl.addTarget(self, action: #selector(segmentedControlSwitch), for: .valueChanged)
}
func segmentedControlSwitch(_ sender: FeedViewSC) {
switch feedViewSC.selectedIndex {
case 0:
firstView.isHidden = false
secondView.isHidden = true
case 1:
firstView.isHidden = true
secondView.isHidden = false
default:
break;
}
}
func setupContainerViews() {
firstView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
firstView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
firstView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
firstView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
secondView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
secondView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
secondView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
secondView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
}
override func viewDidAppear(_ animated: Bool) {
let img = UIImage()
self.navigationController?.navigationBar.shadowImage = img
self.navigationController?.navigationBar.setBackgroundImage(img, for: UIBarMetrics.default)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension CGRect {
var wh: (w: CGFloat, h: CGFloat) {
return (size.width, size.height)
}
}
我不确定我在做什么错了。由于某种原因,代码不会在 firstView 和 secondView 之间切换。目前,它只是显示第一个视图。请记住,我是在没有情节提要的情况下以编程方式进行的。
问题似乎出现在 segmentedControlSwitch 方法中。您应该在 switch case 中使用 sender 而不是可能未初始化的局部变量。
func segmentedControlSwitch(_ sender: myTripsSC) {
switch sender.selectedIndex {
case 0:
firstView.isHidden = false
secondView.isHidden = true
case 1:
firstView.isHidden = true
secondView.isHidden = false
default:
break;
}
}
编辑:
你的 vc 应该是这样的:
import UIKit
class FeedViewController: UIViewController {
let feedViewSC = FeedViewSC()
let firstView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let secondView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.blue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let (width, height) = UIScreen.main.bounds.wh
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
view.addSubview(firstView)
view.addSubview(secondView)
setupContainerViews()
firstView.isHidden = false
secondView.isHidden = true
//myTravel.selectedIndex = 0
let feedControl = FeedViewSC(frame: CGRect(x: 65, y: 5, width: width-130, height: 35))
feedControl.autoresizingMask = [.flexibleWidth,.flexibleHeight]
self.navigationController?.navigationBar.addSubview(feedControl)
feedControl.addTarget(self, action: #selector(segmentedControlSwitch), for: .valueChanged)
}
func segmentedControlSwitch(_ sender: FeedViewSC) {
switch sender.selectedIndex {
case 0:
firstView.isHidden = false
secondView.isHidden = true
case 1:
firstView.isHidden = true
secondView.isHidden = false
default:
break;
}
}
func setupContainerViews() {
if #available(iOS 9.0, *) {
firstView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
firstView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
firstView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
firstView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
secondView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
secondView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
secondView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
secondView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
} else {
// Fallback on earlier versions
}
}
override func viewDidAppear(_ animated: Bool) {
let img = UIImage()
self.navigationController?.navigationBar.shadowImage = img
self.navigationController?.navigationBar.setBackgroundImage(img, for: UIBarMetrics.default)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension CGRect {
var wh: (w: CGFloat, h: CGFloat) {
return (size.width, size.height)
}
}
我做了一个自定义的 UIControl:
import UIKit
@IBDesignable class FeedViewSC: UIControl {
fileprivate var labels = [UILabel]()
var thumbView = UIView()
var items: [String] = ["Tab1", "Tab2"] {
didSet {
setupLabels()
}
}
var selectedIndex : Int = 0 {
didSet{
displayNewSelectedIndex()
}
}
@IBInspectable var font : UIFont! = UIFont.systemFont(ofSize: 13) {
didSet {
setFont()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
func setupView() {
layer.cornerRadius = 5
layer.borderColor = UIColor(red: 239/255, green: 239/255, blue: 239/255, alpha: 1).cgColor
layer.borderWidth = 2
backgroundColor = UIColor(red: 239/255, green: 239/255, blue: 239/255, alpha: 1)
setupLabels()
insertSubview(thumbView, at: 0)
}
func setupLabels() {
for label in labels {
label.removeFromSuperview()
}
labels.removeAll(keepingCapacity: true)
for index in 1...items.count {
let label = UILabel(frame: CGRect.zero)
label.text = items[index-1]
label.textAlignment = .center
label.font = UIFont(name: "Nunito",size: 17)
label.textColor = UIColor(red: 51/255, green: 51/255, blue: 51/255, alpha: 1)
self.addSubview(label)
labels.append(label)
}
}
override func layoutSubviews() {
super.layoutSubviews()
var selectFrame = self.bounds
let newWidth = selectFrame.width / CGFloat(items.count)
selectFrame.size.width = newWidth
thumbView.frame = selectFrame
thumbView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1)
thumbView.layer.cornerRadius = 5
let labelHeight = self.bounds.height
let labelWidth = self.bounds.width / CGFloat(labels.count)
for index in 0...labels.count - 1 {
let label = labels[index]
let xPosition = CGFloat(index) * labelWidth
label.frame = CGRect(x: xPosition, y: 0, width: labelWidth, height: labelHeight)
}
}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
let location = touch.location(in: self)
var calculatedIndex: Int?
for (index, item) in labels.enumerated() {
if item.frame.contains(location){
calculatedIndex = index
}
}
if calculatedIndex != nil {
selectedIndex = calculatedIndex!
sendActions(for: .valueChanged)
}
return false
}
func displayNewSelectedIndex (){
if(self.selectedIndex == -1){
self.selectedIndex = self.items.count-1
}
let label = labels[selectedIndex]
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 0.90, initialSpringVelocity: 0.8, options: [], animations: {
self.thumbView.frame = label.frame
}, completion: nil)
}
func setFont(){
for item in labels {
item.font = font
}
}
}
我将它嵌入到我的 ViewController 中并尝试让它以编程方式在两个视图之间切换:
import UIKit
class FeedViewController: UIViewController {
let feedViewSC = FeedViewSC()
let firstView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let secondView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.blue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let (width, height) = UIScreen.main.bounds.wh
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
view.addSubview(firstView)
view.addSubview(secondView)
setupContainerViews()
firstView.isHidden = false
secondView.isHidden = true
myTravel.selectedIndex = 0
let feedControl = FeedViewSC(frame: CGRect(x: 65, y: 5, width: width-130, height: 35))
feedControl.autoresizingMask = [.flexibleWidth,.flexibleHeight]
self.navigationController?.navigationBar.addSubview(feedControl)
feedControl.addTarget(self, action: #selector(segmentedControlSwitch), for: .valueChanged)
}
func segmentedControlSwitch(_ sender: FeedViewSC) {
switch feedViewSC.selectedIndex {
case 0:
firstView.isHidden = false
secondView.isHidden = true
case 1:
firstView.isHidden = true
secondView.isHidden = false
default:
break;
}
}
func setupContainerViews() {
firstView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
firstView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
firstView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
firstView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
secondView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
secondView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
secondView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
secondView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
}
override func viewDidAppear(_ animated: Bool) {
let img = UIImage()
self.navigationController?.navigationBar.shadowImage = img
self.navigationController?.navigationBar.setBackgroundImage(img, for: UIBarMetrics.default)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension CGRect {
var wh: (w: CGFloat, h: CGFloat) {
return (size.width, size.height)
}
}
我不确定我在做什么错了。由于某种原因,代码不会在 firstView 和 secondView 之间切换。目前,它只是显示第一个视图。请记住,我是在没有情节提要的情况下以编程方式进行的。
问题似乎出现在 segmentedControlSwitch 方法中。您应该在 switch case 中使用 sender 而不是可能未初始化的局部变量。
func segmentedControlSwitch(_ sender: myTripsSC) {
switch sender.selectedIndex {
case 0:
firstView.isHidden = false
secondView.isHidden = true
case 1:
firstView.isHidden = true
secondView.isHidden = false
default:
break;
}
}
编辑: 你的 vc 应该是这样的:
import UIKit
class FeedViewController: UIViewController {
let feedViewSC = FeedViewSC()
let firstView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let secondView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.blue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let (width, height) = UIScreen.main.bounds.wh
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
view.addSubview(firstView)
view.addSubview(secondView)
setupContainerViews()
firstView.isHidden = false
secondView.isHidden = true
//myTravel.selectedIndex = 0
let feedControl = FeedViewSC(frame: CGRect(x: 65, y: 5, width: width-130, height: 35))
feedControl.autoresizingMask = [.flexibleWidth,.flexibleHeight]
self.navigationController?.navigationBar.addSubview(feedControl)
feedControl.addTarget(self, action: #selector(segmentedControlSwitch), for: .valueChanged)
}
func segmentedControlSwitch(_ sender: FeedViewSC) {
switch sender.selectedIndex {
case 0:
firstView.isHidden = false
secondView.isHidden = true
case 1:
firstView.isHidden = true
secondView.isHidden = false
default:
break;
}
}
func setupContainerViews() {
if #available(iOS 9.0, *) {
firstView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
firstView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
firstView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
firstView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
secondView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
secondView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 8).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
secondView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
} else {
// Fallback on earlier versions
}
if #available(iOS 9.0, *) {
secondView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
} else {
// Fallback on earlier versions
}
}
override func viewDidAppear(_ animated: Bool) {
let img = UIImage()
self.navigationController?.navigationBar.shadowImage = img
self.navigationController?.navigationBar.setBackgroundImage(img, for: UIBarMetrics.default)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension CGRect {
var wh: (w: CGFloat, h: CGFloat) {
return (size.width, size.height)
}
}