Inverse UIlabel text color when its frame intersects an UIView

前端 未结 4 1436
盖世英雄少女心
盖世英雄少女心 2020-12-29 11:43

Hi Im trying to change the text color of a UILabel in the case when the labels rect intersects an UIView, i was thinking maybe there is a property or something i can use. L

相关标签:
4条回答
  • 2020-12-29 11:46

    Built an example in Swift for anyone that's looking for a practical application. Great guidance on this danh - thanks!


    import UIKit
    
    class CDSlideView: UIView {
    
        var leftBackView: UIView!
        var leftBackLabel: UILabel!
        var leftFrontView: UIView!
        var leftFrontLabel: UILabel!
    
        var rightBackView: UIView!
        var rightBackLabel: UILabel!
        var rightFrontView: UIView!
        var rightFrontLabel: UILabel!
    
        var foregroundView: UIView!
        var backgroundView: UIView!
    
        var slideGesture: UIPanGestureRecognizer!
    
        let lightColor: UIColor = UIColor.whiteColor()
        let darkColor: UIColor = UIColor.blueColor()
        let leftText: String = "Search"
        let rightText: String = "New"
    
        var viewWidth: CGFloat!
        var viewHeight: CGFloat!
        var leftOrigin: CGFloat!
        var rightOrigin: CGFloat!
        var foregroundPadding: CGFloat = 4
    
        override init(frame: CGRect) {
            super.init(frame: frame)
    
            // Init variables variables
            viewWidth = self.frame.size.width
            viewHeight = self.frame.size.height
            leftOrigin = foregroundPadding / 2
            rightOrigin = (viewWidth - foregroundPadding) / 2 + foregroundPadding / 2
    
            backgroundView = UIView()
            backgroundView.frame = CGRectMake(0, 0, viewWidth, viewHeight)
            backgroundView.layer.cornerRadius = backgroundView.frame.size.height / 2
            self.addSubview(backgroundView)
    
            leftBackView = UIView()
            leftBackView.frame = CGRectMake(0, 0, backgroundView.frame.size.width / 2, backgroundView.frame.size.height)
            self.backgroundView.addSubview(leftBackView)
    
            leftBackLabel = UILabel()
            leftBackLabel.frame = CGRectMake(0, 0, leftBackView.frame.size.width, leftBackView.frame.size.height)
            leftBackLabel.font = UIFont.systemFontOfSize(13, weight: UIFontWeightSemibold)
            leftBackLabel.backgroundColor = UIColor.clearColor()
            leftBackLabel.lineBreakMode = .ByClipping
            leftBackLabel.textAlignment = .Center
            self.leftBackView.addSubview(leftBackLabel)
    
            rightBackView = UIView()
            rightBackView.frame = CGRectMake(backgroundView.frame.size.width / 2, 0, backgroundView.frame.size.width / 2, backgroundView.frame.size.height)
            self.backgroundView.addSubview(rightBackView)
    
            rightBackLabel = UILabel()
            rightBackLabel.frame = CGRectMake(0, 0, rightBackView.frame.size.width, rightBackView.frame.size.height)
            rightBackLabel.font = UIFont.systemFontOfSize(13, weight: UIFontWeightSemibold)
            rightBackLabel.backgroundColor = UIColor.clearColor()
            rightBackLabel.lineBreakMode = .ByClipping
            rightBackLabel.textAlignment = .Center
            self.rightBackView.addSubview(rightBackLabel)
    
            foregroundView = UIView()
            foregroundView.frame = CGRectMake(foregroundPadding / 2, foregroundPadding / 2, (backgroundView.frame.size.width - foregroundPadding) / 2, backgroundView.frame.size.height - foregroundPadding)
            foregroundView.clipsToBounds = true
            foregroundView.layer.cornerRadius = (foregroundView.frame.size.height - foregroundPadding / 2) / 2
            self.addSubview(foregroundView)
    
            slideGesture = UIPanGestureRecognizer(target: self, action: #selector(CDSlideView.slideAction))
            self.foregroundView.addGestureRecognizer(slideGesture)
    
            leftFrontView = UIView()
            leftFrontView.frame = CGRectMake(0, 0, backgroundView.frame.size.width / 2, backgroundView.frame.size.height)
            self.foregroundView.addSubview(leftFrontView)
    
            leftFrontLabel = UILabel()
            leftFrontLabel.font = UIFont.systemFontOfSize(13, weight: UIFontWeightSemibold)
            leftFrontLabel.backgroundColor = UIColor.clearColor()
            leftFrontLabel.translatesAutoresizingMaskIntoConstraints = false
            leftFrontLabel.lineBreakMode = .ByClipping
            leftFrontLabel.textAlignment = .Center
            self.leftFrontView.addSubview(leftFrontLabel)
    
            let leftFrontLabelLeadingConstraint = NSLayoutConstraint(item: leftFrontLabel, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1, constant: self.backgroundView.frame.origin.x)
            self.addConstraint(leftFrontLabelLeadingConstraint)
    
            let leftFrontLabelTopConstraint = NSLayoutConstraint(item: leftFrontLabel, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: self.backgroundView.frame.origin.y)
            self.addConstraint(leftFrontLabelTopConstraint)
    
            let leftFrontLabelWidthConstraint = NSLayoutConstraint(item: leftFrontLabel, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: leftFrontView.frame.size.width)
            self.addConstraint(leftFrontLabelWidthConstraint)
    
            let leftFrontLabelHeightConstraint = NSLayoutConstraint(item: leftFrontLabel, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: leftFrontView.frame.size.height)
            self.addConstraint(leftFrontLabelHeightConstraint)
    
            rightFrontView = UIView()
            rightFrontView.frame = CGRectMake(backgroundView.frame.size.width / 2, 0, backgroundView.frame.size.width / 2, backgroundView.frame.size.height)
            self.foregroundView.addSubview(rightFrontView)
    
            rightFrontLabel = UILabel()
            rightFrontLabel.font = UIFont.systemFontOfSize(13, weight: UIFontWeightSemibold)
            rightFrontLabel.backgroundColor = UIColor.clearColor()
            rightFrontLabel.translatesAutoresizingMaskIntoConstraints = false
            rightFrontLabel.lineBreakMode = .ByClipping
            rightFrontLabel.textAlignment = .Center
            self.rightFrontView.addSubview(rightFrontLabel)
    
            let rightFrontLabelTrailingConstraint = NSLayoutConstraint(item: self, attribute: .Trailing, relatedBy: .Equal, toItem: rightFrontLabel, attribute: .Trailing, multiplier: 1, constant: self.backgroundView.frame.origin.x)
            self.addConstraint(rightFrontLabelTrailingConstraint)
    
            let rightFrontLabelTopConstraint = NSLayoutConstraint(item: rightFrontLabel, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: self.backgroundView.frame.origin.y)
            self.addConstraint(rightFrontLabelTopConstraint)
    
            let rightFrontLabelWidthConstraint = NSLayoutConstraint(item: rightFrontLabel, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: rightFrontView.frame.size.width)
            self.addConstraint(rightFrontLabelWidthConstraint)
    
            let rightFrontLabelHeightConstraint = NSLayoutConstraint(item: rightFrontLabel, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: rightFrontView.frame.size.height)
            self.addConstraint(rightFrontLabelHeightConstraint)
    
            let leftTapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(CDSlideView.leftTap(_:)))
            self.leftBackView.addGestureRecognizer(leftTapGesture)
    
            let rightTapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(CDSlideView.rightTap(_:)))
            self.rightBackView.addGestureRecognizer(rightTapGesture)
    
            self.setLabelText(leftText, rightText: rightText)
            self.setLightColor(lightColor)
            self.setDarkColor(darkColor)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        // MARK: Setup
        func setLightColor(lightColor: UIColor) {
            let lightColor = lightColor
            self.foregroundView.backgroundColor = lightColor
            self.leftBackLabel.textColor = lightColor
            self.rightBackLabel.textColor = lightColor
        }
    
        func setDarkColor(darkColor: UIColor) {
            let darkColor = darkColor
            self.backgroundView.backgroundColor = darkColor
            self.leftFrontLabel.textColor = darkColor
            self.rightFrontLabel.textColor = darkColor
        }
    
        func setLabelText(leftText: String, rightText: String) {
            self.leftFrontLabel.text = leftText
            self.leftBackLabel.text = leftText
            self.rightFrontLabel.text = rightText
            self.rightBackLabel.text = rightText
        }
    
        // MARK: Actions
        func slideAction(sender: UIPanGestureRecognizer) {
            if sender.state == .Began || sender.state == .Changed {
                let translation = sender.translationInView(self)
    
                // Calculate where the user is trying to drag
                var newCenter: CGPoint = CGPointMake(sender.view!.center.x + translation.x, sender.view!.center.y)
    
                // Limit bounds & update center
                newCenter.x = max(self.frame.size.width * 0.25 + foregroundPadding / 2, newCenter.x)
                newCenter.x = min(self.frame.size.width * 0.75 - foregroundPadding / 2, newCenter.x)
    
                // Set new center
                sender.view!.center = newCenter
                sender.setTranslation(CGPointMake(0,0), inView: self)
            } else if sender.state == .Ended {
                let senderVCX = sender.view?.center.x
    
                // Snap to side
                if senderVCX <= viewWidth / 2 {
                    print("called left")
                    sender.view?.frame.origin.x = self.leftOrigin
                } else {
                    print("called right")
                    sender.view?.frame.origin.x = self.rightOrigin
                }
            }
        }
    
        func leftTap(sender: UITapGestureRecognizer) {
            UIView.animateWithDuration(0.05) {
                self.foregroundView.frame.origin.x = self.leftOrigin
            }
        }
    
        func rightTap(sender: UITapGestureRecognizer) {
            UIView.animateWithDuration(0.05) {
                self.foregroundView.frame.origin.x = self.rightOrigin
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-29 11:50

    I would suggest you to have a look at these methods:

    You may check how much of your string overlaps with the view by checking NSString's size, with this method:

    [yourString sizeWithFont:yourFont constrainedToSize:maximumAllowedSize];
    

    Then you can use a NSMutableAttributedString for setting part of the label's strings to one color and the latter part with another color.

    //Just an example usage 
    //It sets the color of characters starting from 3 to the end to blue
    [str addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(3, str.length)];
    
    
    //Now you have to set your string as attributed text just like below
    //UILabels now support attributed strings by default which is quite handy
    
    [yourLabel setAttributedString:str];
    
    0 讨论(0)
  • 2020-12-29 12:05

    Good puzzle! Here's what I would do:

    1. Two UIViews. Let's call one the background and the other the progressBar. progressBar is stacked on top of background with the same origin on their common superview.
    2. They both have a UILabel as subview, and both labels at the same origin relative to their parent. background has a dark backgroundColor and it's label has light textColor and the progress view has things the other way around.
    3. progressBar has a narrower frame width than background and has clipsToBounds==YES

    The trick is, with the views' origins the same and the labels' origins the same, and clipsToBounds on the top view, everything is going to look right.

    Drop those two views into a new UIView subclass called ReallyCoolProgressView, and give it one public method:

    -(void)setProgress:(float)progress progress is a number from 0.0 to 1.0. The method scales the progressBar width and sets both label's text @"Progress %f", progress*100

    0 讨论(0)
  • 2020-12-29 12:09

    Take a look at this tutorial for creating alpha masks with text. Using this technique you can implement a standard progress bar that moves across both the foreground and the background view to achieve the effect you want.

    0 讨论(0)
提交回复
热议问题