web-dev-qa-db-ja.com

UISegmentedControlで選択された項目の下枠のみを表示する方法は?

私はiOS開発に非常に慣れていないので、コース用のアプリを作成しているときに問題が発生しました。

セグメント化されたコントロールを作成し、そのinit関数(以下を参照)が、セグメント化されたコントロールを含むビューコントローラークラスで呼び出されています。次のように、セグメント化されたコントロールクラスからすべての境界線とセグメント化されたコントロールの境界線を削除することができました。

import Foundation
import UIKit

class CashSegmentedControl: UISegmentedControl{

func initUI(){
    removeBorders()
}

func removeBorders(){
    self.tintColor = UIColor.clear

}

This is what my result looks like currently

セグメントが選択されているときに、各セグメントの下に線を引きたい(Instagramと同様)

This is a sample of what I want it to look like

私はたくさん検索して、StackOverflowのいくつかの投稿に出くわしましたが、それらは古いバージョンのSwiftのようです。私はこの問題についてどんな助けでも本当に感謝します、そして国境をカスタマイズするためのより良い解決策があれば(私がやったこと以外に)、もっと学びたいです!

どうもありがとう :)

13
Richa Netto

別のSwift file(command + N-> New File)に次のコードを追加します:

_extension UISegmentedControl{
    func removeBorder(){
        let backgroundImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: self.bounds.size)
        self.setBackgroundImage(backgroundImage, for: .normal, barMetrics: .default)
        self.setBackgroundImage(backgroundImage, for: .selected, barMetrics: .default)
        self.setBackgroundImage(backgroundImage, for: .highlighted, barMetrics: .default)

        let deviderImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: CGSize(width: 1.0, height: self.bounds.size.height))
        self.setDividerImage(deviderImage, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default)
        self.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.gray], for: .normal)
        self.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0)], for: .selected)
    }

    func addUnderlineForSelectedSegment(){
        removeBorder()
        let underlineWidth: CGFloat = self.bounds.size.width / CGFloat(self.numberOfSegments)
        let underlineHeight: CGFloat = 2.0
        let underlineXPosition = CGFloat(selectedSegmentIndex * Int(underlineWidth))
        let underLineYPosition = self.bounds.size.height - 1.0
        let underlineFrame = CGRect(x: underlineXPosition, y: underLineYPosition, width: underlineWidth, height: underlineHeight)
        let underline = UIView(frame: underlineFrame)
        underline.backgroundColor = UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0)
        underline.tag = 1
        self.addSubview(underline)
    }

    func changeUnderlinePosition(){
        guard let underline = self.viewWithTag(1) else {return}
        let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(selectedSegmentIndex)
        UIView.animate(withDuration: 0.1, animations: {
            underline.frame.Origin.x = underlineFinalXPosition
        })
    }
}

extension UIImage{

    class func getColoredRectImageWith(color: CGColor, andSize size: CGSize) -> UIImage{
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        let graphicsContext = UIGraphicsGetCurrentContext()
        graphicsContext?.setFillColor(color)
        let rectangle = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
        graphicsContext?.fill(rectangle)
        let rectangleImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return rectangleImage!
    }
}
_

次に、segmentedControl.addUnderlineForSelectedSegment()メソッドからviewDidLoad()を呼び出し、セグメント化されたコントロールの_@IBAction_メソッドを次のように作成します。

_@IBAction func segmentedControlDidChange(_ sender: UISegmentedControl){
        segmentedControl.changeUnderlinePosition()
    }
_

次に、このメソッド内からsegmentedControl.changeUnderlinePosition()を呼び出します。

ストーリーボードのセグメント化されたコントロールを、作成した_@IBAction_メソッドに接続することを忘れないでください。

非常に重要:ストーリーボードで自動レイアウトを使用して、セグメント化されたコントロールのサイズと位置を決定することを忘れないでください。

これが結果です:

enter image description here

enter image description here

enter image description here

他にご不明な点がありましたら、お気軽にご質問ください:)

29
fja

A.Jamの回答Xcode 9.3、Swift 4.2バージョン

import UIKit

extension UISegmentedControl {
    func removeBorder(){
        let backgroundImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: self.bounds.size)
        self.setBackgroundImage(backgroundImage, for: .normal, barMetrics: .default)
        self.setBackgroundImage(backgroundImage, for: .selected, barMetrics: .default)
        self.setBackgroundImage(backgroundImage, for: .highlighted, barMetrics: .default)

        let deviderImage = UIImage.getColoredRectImageWith(color: UIColor.white.cgColor, andSize: CGSize(width: 1.0, height: self.bounds.size.height))
        self.setDividerImage(deviderImage, forLeftSegmentState: .selected, rightSegmentState: .normal, barMetrics: .default)
        self.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.gray], for: .normal)
        self.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0)], for: .selected)
    }

    func addUnderlineForSelectedSegment(){
        removeBorder()
        let underlineWidth: CGFloat = self.bounds.size.width / CGFloat(self.numberOfSegments)
        let underlineHeight: CGFloat = 2.0
        let underlineXPosition = CGFloat(selectedSegmentIndex * Int(underlineWidth))
        let underLineYPosition = self.bounds.size.height - 1.0
        let underlineFrame = CGRect(x: underlineXPosition, y: underLineYPosition, width: underlineWidth, height: underlineHeight)
        let underline = UIView(frame: underlineFrame)
        underline.backgroundColor = UIColor(red: 67/255, green: 129/255, blue: 244/255, alpha: 1.0)
        underline.tag = 1
        self.addSubview(underline)
    }

    func changeUnderlinePosition(){
        guard let underline = self.viewWithTag(1) else {return}
        let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(selectedSegmentIndex)
        UIView.animate(withDuration: 0.1, animations: {
            underline.frame.Origin.x = underlineFinalXPosition
        })
    }
}

extension UIImage {

    class func getColoredRectImageWith(color: CGColor, andSize size: CGSize) -> UIImage{
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        let graphicsContext = UIGraphicsGetCurrentContext()
        graphicsContext?.setFillColor(color)
        let rectangle = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
        graphicsContext?.fill(rectangle)
        let rectangleImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return rectangleImage!
    }
}
7
swift2geek

XcodeでのA.Jamの回答10.1、Swift 4.2 version-IImage Extensionなし

そしてすべてのsegmentIndexesのための灰色の下線

extension UISegmentedControl {

  func removeBorder(){

    self.tintColor = UIColor.clear
    self.backgroundColor = UIColor.clear
    self.setTitleTextAttributes( [NSAttributedString.Key.foregroundColor : UIColor.orange], for: .selected)
    self.setTitleTextAttributes( [NSAttributedString.Key.foregroundColor : UIColor.gray], for: .normal)

  }

  func setupSegment() {
    self.removeBorder()
    let segmentUnderlineWidth: CGFloat = self.bounds.width
    let segmentUnderlineHeight: CGFloat = 2.0
    let segmentUnderlineXPosition = self.bounds.minX
    let segmentUnderLineYPosition = self.bounds.size.height - 1.0
    let segmentUnderlineFrame = CGRect(x: segmentUnderlineXPosition, y: segmentUnderLineYPosition, width: segmentUnderlineWidth, height: segmentUnderlineHeight)
    let segmentUnderline = UIView(frame: segmentUnderlineFrame)
    segmentUnderline.backgroundColor = UIColor.gray

    self.addSubview(segmentUnderline)
    self.addUnderlineForSelectedSegment()

  }
  func addUnderlineForSelectedSegment(){

    let underlineWidth: CGFloat = self.bounds.size.width / CGFloat(self.numberOfSegments)
    let underlineHeight: CGFloat = 2.0
    let underlineXPosition = CGFloat(selectedSegmentIndex * Int(underlineWidth))
    let underLineYPosition = self.bounds.size.height - 1.0
    let underlineFrame = CGRect(x: underlineXPosition, y: underLineYPosition, width: underlineWidth, height: underlineHeight)
    let underline = UIView(frame: underlineFrame)
    underline.backgroundColor = UIColor.orange
    underline.tag = 1
    self.addSubview(underline)
  }

  func changeUnderlinePosition(){
    guard let underline = self.viewWithTag(1) else {return}
    let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(selectedSegmentIndex)
    underline.frame.Origin.x = underlineFinalXPosition

  }
}
2
Kobi

あなたはこれを使うことができます

let segmentBottomBorder = CALayer()
segmentBottomBorder?.borderColor = UIColor.blue.cgColor
segmentBottomBorder?.borderWidth = 3
let x = CGFloat(sender.selectedSegmentIndex) * width
let y = sender.frame.size.height - (segmentBottomBorder?.borderWidth)!
let width: CGFloat = sender.frame.size.width/3
segmentBottomBorder?.frame = CGRect(x: x, y: y, width: width, height: (segmentBottomBorder?.borderWidth)!)
sender.layer.addSublayer(segmentBottomBorder!)
2
Gabrail

A.Jamsの回答Swift 5.1 Xcode 11.

import Foundation
extension UISegmentedControl {

    func removeBorder(){

        self.tintColor = UIColor.clear
        self.backgroundColor = UIColor.clear
        self.setTitleTextAttributes( [NSAttributedString.Key.foregroundColor : UIColor.stavkrugDarkBlue], for: .selected)
        self.setTitleTextAttributes( [NSAttributedString.Key.foregroundColor : UIColor.gray], for: .normal)
        if #available(iOS 13.0, *) {
            self.selectedSegmentTintColor = UIColor.clear
        } 

    }

    func setupSegment() {
        self.removeBorder()
        let segmentUnderlineWidth: CGFloat = self.bounds.width
        let segmentUnderlineHeight: CGFloat = 2.0
        let segmentUnderlineXPosition = self.bounds.minX
        let segmentUnderLineYPosition = self.bounds.size.height - 1.0
        let segmentUnderlineFrame = CGRect(x: segmentUnderlineXPosition, y: segmentUnderLineYPosition, width: segmentUnderlineWidth, height: segmentUnderlineHeight)
        let segmentUnderline = UIView(frame: segmentUnderlineFrame)
        segmentUnderline.backgroundColor = UIColor.clear

        self.addSubview(segmentUnderline)
        self.addUnderlineForSelectedSegment()
    }

    func addUnderlineForSelectedSegment(){

        let underlineWidth: CGFloat = self.bounds.size.width / CGFloat(self.numberOfSegments)
        let underlineHeight: CGFloat = 2.0
        let underlineXPosition = CGFloat(selectedSegmentIndex * Int(underlineWidth))
        let underLineYPosition = self.bounds.size.height - 1.0
        let underlineFrame = CGRect(x: underlineXPosition, y: underLineYPosition, width: underlineWidth, height: underlineHeight)
        let underline = UIView(frame: underlineFrame)
        underline.backgroundColor = UIColor.stavkrugDarkBlue
        underline.tag = 1
        self.addSubview(underline)


    }

    func changeUnderlinePosition(){
        guard let underline = self.viewWithTag(1) else {return}
        let underlineFinalXPosition = (self.bounds.width / CGFloat(self.numberOfSegments)) * CGFloat(selectedSegmentIndex)
        underline.frame.Origin.x = underlineFinalXPosition

    }
}
0
Dmih