web-dev-qa-db-ja.com

Swift)で範囲スライダーを実装する方法

Range Sliderを実装しようとしていますが、 NMRangeSlider というカスタムコントロールを使用しました。

しかし、使用するとスライダーがまったく表示されません。それはすべてObjective-Cで書かれているからでもありますか?

これは私が現在それを実装した方法です:

var rangeSlider = NMRangeSlider(frame: CGRectMake(16, 6, 275, 34))
rangeSlider.lowerValue = 0.54
rangeSlider.upperValue = 0.94
self.view.addSubview(rangeSlider)
8
Rawan

更新:

真っ白だったので見えませんでした。したがって、他のフレームワークを使用せず、これに固執することなく、ソリューションはすべてのコンポーネントのすべてのビューを設定する必要があります。そうすれば、適切に表示されます。

enter image description here


以前Objective-Cコードで使用したのと同じようにSwiftにインポートしようとしましたが、うまくいきませんでした。すべてを適切に設定し、viewDidLoad()に追加した場合またはviewDidAppear()の場合、何も表示されません。ただし、View Debug Hierarchyと入力すると、スライダーは実際にはisキャンバス上にあります:

enter image description here

ただし、ビューに追加する前に設定したすべての色でレンダリングされるわけではありません。記録のために-これは私が使用したコードです:

override func viewDidAppear(animated: Bool) {
    var rangeSlider = NMRangeSlider(frame: CGRectMake(50, 50, 275, 34))
    rangeSlider.lowerValue = 0.54
    rangeSlider.upperValue = 0.94

    let range = 10.0
    let oneStep = 1.0 / range
    let minRange: Float = 0.05
    rangeSlider.minimumRange = minRange

    let bgImage = UIView(frame: rangeSlider.frame)
    bgImage.backgroundColor = .greenColor()
    rangeSlider.trackImage = bgImage.pb_takeSnapshot()

    let trackView = UIView(frame: CGRectMake(0, 0, rangeSlider.frame.size.width, 29))
    trackView.backgroundColor = .whiteColor()
    trackView.opaque = false
    trackView.alpha = 0.3
    rangeSlider.trackImage = UIImage(named: "")

    let lowerThumb = UIView(frame: CGRectMake(0, 0, 8, 29))
    lowerThumb.backgroundColor = .whiteColor()
    let lowerThumbHigh = UIView(frame: CGRectMake(0, 0, 8, 29))
    lowerThumbHigh.backgroundColor = UIColor.blueColor()

    rangeSlider.lowerHandleImageNormal = lowerThumb.pb_takeSnapshot()
    rangeSlider.lowerHandleImageHighlighted = lowerThumbHigh.pb_takeSnapshot()
    rangeSlider.upperHandleImageNormal = lowerThumb.pb_takeSnapshot()
    rangeSlider.upperHandleImageHighlighted = lowerThumbHigh.pb_takeSnapshot()

    self.view.addSubview(rangeSlider)

    self.view.backgroundColor = .lightGrayColor()
}

この質問 で説明されているUIImageとしてUIViewをキャプチャするためのメソッドを使用する:

extension UIView {
    func pb_takeSnapshot() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.mainScreen().scale)
        drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

その他の解決策:

sgwilly/RangeSlider を試すこともできます。代わりに、Swiftで記述されているため、ブリッジヘッダーも必要ありません。

2
Michal

カスタムレンジスライダーを作成するには、ここで良い解決策を見つけました: レンジファインダーチュートリアルiOS 8 しかし、これはSwift 3でプロジェクトに必要でした。これを=に更新しましたSwift 3 iOS 10ここ:

  1. メインのViewControllerで、これをviewDidLayOutに追加して、範囲スライダーを表示します。

    override func viewDidLayoutSubviews() {
       let margin: CGFloat = 20.0
       let width = view.bounds.width - 2.0 * margin
       rangeSlider.frame = CGRect(x: margin, y: margin + topLayoutGuide.length + 170, width: width, height: 31.0)
    }
    
  2. viewDidLayoutSubviews()の下にスライダー出力を出力するヘルパー関数を作成します

    func rangeSliderValueChanged() { //rangeSlider: RangeSlider
        print("Range slider value changed: \(rangeSlider.lowerValue) \(rangeSlider.upperValue) ")//(\(rangeSlider.lowerValue) \(rangeSlider.upperValue))
    }
    
  3. ファイルRangeSlider.Swiftを作成し、これを追加します。

    import UIKit
    
    import QuartzCore
    
    class RangeSlider: UIControl {
    
     var minimumValue = 0.0
     var maximumValue = 1.0
     var lowerValue = 0.2
     var upperValue = 0.8
    
     let trackLayer = RangeSliderTrackLayer()//= CALayer() defined in RangeSliderTrackLayer.Swift
     let lowerThumbLayer = RangeSliderThumbLayer()//CALayer()
     let upperThumbLayer = RangeSliderThumbLayer()//CALayer()
     var previousLocation = CGPoint()
    
     var trackTintColor = UIColor(white: 0.9, alpha: 1.0)
     var trackHighlightTintColor = UIColor(red: 0.0, green: 0.45, blue: 0.94, alpha: 1.0)
     var thumbTintColor = UIColor.white
    
     var curvaceousness : CGFloat = 1.0
    
     var thumbWidth: CGFloat {
       return CGFloat(bounds.height)
     }
    
     override init(frame: CGRect) {
       super.init(frame: frame)
    
       trackLayer.rangeSlider = self
       trackLayer.contentsScale = UIScreen.main.scale
       layer.addSublayer(trackLayer)
    
       lowerThumbLayer.rangeSlider = self
       lowerThumbLayer.contentsScale = UIScreen.main.scale
       layer.addSublayer(lowerThumbLayer)
    
       upperThumbLayer.rangeSlider = self
       upperThumbLayer.contentsScale = UIScreen.main.scale
       layer.addSublayer(upperThumbLayer)
    
      }
    
     required init?(coder: NSCoder) {
       super.init(coder: coder)
     }
    
     func updateLayerFrames() {
       trackLayer.frame = bounds.insetBy(dx: 0.0, dy: bounds.height / 3)
       trackLayer.setNeedsDisplay()
    
       let lowerThumbCenter = CGFloat(positionForValue(value: lowerValue))
    
       lowerThumbLayer.frame = CGRect(x: lowerThumbCenter - thumbWidth / 2.0, y: 0.0,
                                   width: thumbWidth, height: thumbWidth)
       lowerThumbLayer.setNeedsDisplay()
    
       let upperThumbCenter = CGFloat(positionForValue(value: upperValue))
       upperThumbLayer.frame = CGRect(x: upperThumbCenter - thumbWidth / 2.0, y: 0.0,
                                   width: thumbWidth, height: thumbWidth)
       upperThumbLayer.setNeedsDisplay()
     }
    
     func positionForValue(value: Double) -> Double {
      return Double(bounds.width - thumbWidth) * (value - minimumValue) /
        (maximumValue - minimumValue) + Double(thumbWidth / 2.0)
     }
    
      override var frame: CGRect {
       didSet {
          updateLayerFrames()
        }
      }
    
       override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
          previousLocation = touch.location(in: self)
    
          // Hit test the thumb layers
          if lowerThumbLayer.frame.contains(previousLocation) {
            lowerThumbLayer.highlighted = true
          } else if upperThumbLayer.frame.contains(previousLocation) {
            upperThumbLayer.highlighted = true
          }
    
           return lowerThumbLayer.highlighted || upperThumbLayer.highlighted
       }
    
       func boundValue(value: Double, toLowerValue lowerValue: Double, upperValue: Double) -> Double {
         return min(max(value, lowerValue), upperValue)
       }
    
       override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
         let location = touch.location(in: self)
    
         // 1. Determine by how much the user has dragged
         let deltaLocation = Double(location.x - previousLocation.x)
         let deltaValue = (maximumValue - minimumValue) * deltaLocation / Double(bounds.width - thumbWidth)
    
          previousLocation = location
    
          // 2. Update the values
         if lowerThumbLayer.highlighted {
            lowerValue += deltaValue
            lowerValue = boundValue(value: lowerValue, toLowerValue: minimumValue, upperValue: upperValue)
        } else if upperThumbLayer.highlighted {
          upperValue += deltaValue
          upperValue = boundValue(value: upperValue, toLowerValue: lowerValue, upperValue: maximumValue)
        }
    
        // 3. Update the UI
        CATransaction.begin()
        CATransaction.setDisableActions(true)
    
        updateLayerFrames()
    
        CATransaction.commit()
    
         sendActions(for: .valueChanged)
    
          return true
     }
    
      override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
        lowerThumbLayer.highlighted = false
        upperThumbLayer.highlighted = false
      }
    }
    
  4. 次に、サムレイヤーサブクラスファイルRangeSliderThumbLayer.Swiftを追加し、これを追加します。

      import UIKit
    
      class RangeSliderThumbLayer: CALayer {
         var highlighted = false
         weak var rangeSlider: RangeSlider?
    
      override func draw(in ctx: CGContext) {
        if let slider = rangeSlider {
          let thumbFrame = bounds.insetBy(dx: 2.0, dy: 2.0)
          let cornerRadius = thumbFrame.height * slider.curvaceousness / 2.0
          let thumbPath = UIBezierPath(roundedRect: thumbFrame, cornerRadius: cornerRadius)
    
          // Fill - with a subtle shadow
          let shadowColor = UIColor.gray
          ctx.setShadow(offset: CGSize(width: 0.0, height: 1.0), blur: 1.0, color: shadowColor.cgColor)
          ctx.setFillColor(slider.thumbTintColor.cgColor)
          ctx.addPath(thumbPath.cgPath)
          ctx.fillPath()
    
        // Outline
        ctx.setStrokeColor(shadowColor.cgColor)
        ctx.setLineWidth(0.5)
        ctx.addPath(thumbPath.cgPath)
        ctx.strokePath()
    
        if highlighted {
            ctx.setFillColor(UIColor(white: 0.0, alpha: 0.1).cgColor)
            ctx.addPath(thumbPath.cgPath)
            ctx.fillPath()
        }
      }
     }
    }
    
  5. 最後に、トラックレイヤーサブクラスファイルRangeSliderTrackLayer.Swiftを追加し、それに以下を追加します。

     import Foundation
     import UIKit
     import QuartzCore
    
     class RangeSliderTrackLayer: CALayer {
      weak var rangeSlider: RangeSlider?
    
      override func draw(in ctx: CGContext) {
        if let slider = rangeSlider {
          // Clip
          let cornerRadius = bounds.height * slider.curvaceousness / 2.0
          let path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
          ctx.addPath(path.cgPath)
    
          // Fill the track
          ctx.setFillColor(slider.trackTintColor.cgColor)
          ctx.addPath(path.cgPath)
          ctx.fillPath()
    
          // Fill the highlighted range
          ctx.setFillColor(slider.trackHighlightTintColor.cgColor)
          let lowerValuePosition =  CGFloat(slider.positionForValue(value: slider.lowerValue))
          let upperValuePosition = CGFloat(slider.positionForValue(value: slider.upperValue))
          let rect = CGRect(x: lowerValuePosition, y: 0.0, width: upperValuePosition - lowerValuePosition, height: bounds.height)
        ctx.fill(rect)
       }
      }
     }
    

ビルドの実行と取得: enter image description here

4
Brian

このコードを試してください:

override func viewDidLayoutSubviews() {
    let margin: CGFloat = 20.0
    let width = view.bounds.width - 2.0 * margin
    rangeSlider.frame = CGRect(x: margin, y: margin + topLayoutGuide.length,
        width: width, height: 31.0)
}
0
Jay Bhalani

次を使用して範囲スライダーを実装しました: https://github.com/Zengzhihui/RangeSlider

GZRangeSliderクラスには、次のメソッドがあります:private func setLabelText()

その方法では、次のように入力します。

leftTextLayer.frame = CGRectMake(leftHandleLayer.frame.minX-0.5 *(kTextWidth-leftHandleLayer.frame.width)、leftHandleLayer.frame.minY-kTextHeight、kTextWidth、kTextHeight)

rightTextLayer.frame = CGRectMake(rightHandleLayer.frame.minX-0.5 *(kTextWidth-leftHandleLayer.frame.width)、leftTextLayer.frame.minY、kTextWidth、kTextHeight)

下部ラベルと上部ラベルをアニメーション化します。

これは私とSwiftでうまく機能しています..試してみてください..

0