在swift中正确对齐点

z9smfwbn  于 2023-11-16  发布在  Swift
关注(0)|答案(1)|浏览(154)

我目前有这个自定义的UIView显示3点。选定的点是最大的。这是它的外观:


的数据
但问题是,有时当currentPage为0时,它会覆盖第二个点,只显示两个点,但在视图层次结构调试器中,我可以看到第一个点(大点)覆盖了第二个点,只有第三个点可见。
就像这样:



我的代码:

import UIKit

class ExpandedCustomLoopedPageControl: UIView {

// MARK: - start flow in pagenumber  set
    public var numberOfPages: Int = 0 {
        didSet {

            dotViewArray.forEach { $0.removeFromSuperview() }
            dotViewArray.removeAll()

            for _ in 0..<numberOfPages {
                let dotView = UIView()
                dotView.layer.cornerRadius = cornerRadius
                addSubview(dotView)
                dotViewArray.append(dotView)
            }

            isInitialize = true
            setNeedsLayout()
        }
    }

    public var currentPage: Int {
        set {
            if newValue < 0 ||
                newValue >= dotViewArray.count ||
                dotViewArray.count == 0 ||
                newValue == currentPage ||
                inAnimating {
                return
            }

            var animationDuration = 0.1
            if ((  currentPage == (numberOfPages - 1) ) && ( newValue == 0))
                || (currentPage == 0 && (newValue == (numberOfPages - 1))) {
                animationDuration = 0
            }
// MARK: - Shift to the right
            if newValue > currentPage {
                let currentView = dotViewArray[currentPage]
                bringSubviewToFront(currentView)
                inAnimating = true
                UIView.animate(withDuration: animationDuration, animations: {
                    // For the currently selected dot, the x is
                    // unchanged, the width is increased, and several dots
                    // and gap distances are added.
                    let x = currentView.frame.origin.x
                    let y = currentView.frame.origin.y
                    let w = self.currentDotWidth + (self.dotSpace + self.otherDotWidth) * CGFloat(newValue - self.currentPage)
                    let h = currentView.frame.size.height
                    currentView.frame = CGRect(x: x, y: y, width: w, height: h)
                }) { (_) in
                    let endView = self.dotViewArray[newValue]
                    endView.backgroundColor = currentView.backgroundColor
                    endView.frame = currentView.frame
                    self.bringSubviewToFront(endView)

                    currentView.backgroundColor = self.otherDotColor

                    // Shift left one by one
                    let start_X = currentView.frame.origin.x
                    for i in 0..<(newValue - self.currentPage) {

                        let dotView = self.dotViewArray[self.currentPage + i]
                        // shift left
                        let x = start_X + (self.otherDotWidth + self.dotSpace) * CGFloat(i)
                        let y = dotView.frame.origin.y
                        let w = self.otherDotWidth
                        let h = self.dotHeight
                        dotView.frame = CGRect(x: x, y: y, width: w, height: h)
                    }
                    UIView.animate(withDuration: 0.1, animations: {
                        let w = self.currentDotWidth
                        let x = endView.frame.maxX - self.currentDotWidth
                        let y = endView.frame.origin.y
                        let h = endView.frame.size.height
                        endView.frame = CGRect(x: x, y: y, width: w, height: h)
                    }) { (_) in
                        self.currentPageInner = newValue
                        self.inAnimating = false
                    }
                }
            }
 // MARK: - Shift to the Left
            else {
                let currentView = self.dotViewArray[self.currentPage]
                bringSubviewToFront(currentView)
                inAnimating = true

                UIView.animate(withDuration: animationDuration, animations: {
                    // For the currently selected dot, move x to the left, increase the width, increase a few dots and the gap distance
                    let x = currentView.frame.origin.x - (self.dotSpace + self.otherDotWidth) * CGFloat(self.currentPage - newValue)
                    let y = currentView.frame.origin.y
                    let w = self.currentDotWidth + (self.dotSpace + self.otherDotWidth) * CGFloat(self.currentPage - newValue)
                    let h = currentView.frame.size.height
                    currentView.frame = CGRect(x: x, y: y, width: w, height: h)
                }) { (_) in
                    let endView = self.dotViewArray[newValue]
                    endView.backgroundColor = currentView.backgroundColor
                    endView.frame = currentView.frame
                    self.bringSubviewToFront(endView)

                    currentView.backgroundColor = self.otherDotColor

                    // Move the view to the right one by one
                    let start_X = currentView.frame.maxX
                    for i in 0..<(self.currentPage - newValue) {
                        let dotView = self.dotViewArray[self.currentPage - i]
                        let tempFrame = dotView.frame
                        // move right
                        let x = start_X - self.otherDotWidth - (self.otherDotWidth + self.dotSpace) * CGFloat(i)
                        let y = tempFrame.origin.y
                        let w = self.otherDotWidth
                        let h = tempFrame.size.height
                        dotView.frame = CGRect(x: x, y: y, width: w, height: h)
                    }

                    UIView.animate(withDuration: 0.1, animations: {
                        let x = endView.frame.origin.x
                        let y = endView.frame.origin.y
                        let w = self.currentDotWidth
                        let h = endView.frame.size.height
                        endView.frame = CGRect(x: x, y: y, width: w, height: h)
                    }) { (_) in
                        self.currentPageInner = newValue
                        self.inAnimating = false
                    }
                }
            }
        }
        get {
            currentPageInner
        }
    }

// MARK: - properties of pageControl

    public var currentDotWidth: CGFloat = 20
    public var otherDotWidth: CGFloat = 5
    public var dotHeight: CGFloat = 5
    public var dotSpace: CGFloat = 7
    public var cornerRadius: CGFloat = 2.5
    public var currentDotColor: UIColor = Color.lines.color
    public var otherDotColor: UIColor = Color.slider_indicator_bubble.color

    private var currentPageInner: Int = 0
    private var dotViewArray = [UIView]()
    private var isInitialize: Bool = false
    private var inAnimating: Bool = false

// MARK: - init()
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        setupUI()
    }
// MARK: - Setup UI
    private func setupUI() {
        if dotViewArray.isEmpty || isInitialize == false {
            return
        }
        self.isInitialize = false

        let totalWidth = CGFloat(numberOfPages) * (currentDotWidth + dotSpace) - dotSpace
        var currentX = (frame.size.width - totalWidth) / 2

        for (index, dotView) in dotViewArray.enumerated() {
            // Update location
            let width = (index == currentPage ? currentDotWidth : otherDotWidth)
            let height = dotHeight
            let y = (frame.size.height - height) / 2
            dotView.frame = CGRect(x: currentX, y: y, width: width, height: height)

            // Update color
            dotView.backgroundColor = (index == currentPage) ? currentDotColor : otherDotColor

            currentX += width + dotSpace
        }
    }
}

字符串
第一个点不应覆盖第二个和第三个点。

puruo6ea

puruo6ea1#

如果这是你正在寻找的分页效果,请继续阅读以获得不同的方法。


的数据

class DotsViewController: UIViewController {
    
    @IBOutlet private weak var redDot: DotView!
    @IBOutlet private weak var dotMover: UIStepper!
    @IBOutlet private weak var dotStack: UIStackView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        configureStepper()
        redDot.layer.zPosition = 10 //ensures the red dot stays on top during animations
    }
    
    private func configureStepper() {
        dotMover.setDecrementImage(UIImage(systemName: "chevron.left"), for: .normal)
        dotMover.setIncrementImage(UIImage(systemName: "chevron.right"), for: .normal)
        
        dotMover.maximumValue = Double(dotStack.subviews.count - 1) //because we start at index 0
    }

    @IBAction
    private func didModifyStepper(_ sender: UIStepper) {
        let currentValue = Int(sender.value)
        UIView.animate(withDuration: 0.4, animations: { [weak self] in
            guard let strongSelf = self else { return }
            strongSelf.dotStack.removeArrangedSubview(strongSelf.redDot)
            strongSelf.dotStack.insertArrangedSubview(strongSelf.redDot, at: currentValue)
            strongSelf.dotStack.layoutIfNeeded()
        })
    }
}

字符串
其中DotView是:

@IBDesignable
class DotView: UIView {
    @IBInspectable
    var cornerRadius: CGFloat = .zero {
        didSet {
            self.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMaxXMinYCorner]
            self.layer.cornerRadius = self.cornerRadius
            self.clipsToBounds = true
        }
    }
}


自定义分页控件是通过UIStackView和一堆带圆角的UIView来实现的。源代码在github上。


相关问题