如何在SWIFT中实现距离滑块

o4tp2gmn  于 2022-09-19  发布在  Swift
关注(0)|答案(4)|浏览(224)

我正在尝试实现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)
s5a0g9ez

s5a0g9ez1#

为了创建一个定制的Range Slider,我在这里找到了一个很好的解决方案:range finder tutorial iOS 8,但我的项目在Swift 3中需要这个解决方案。我在这里为Swift 3 iOS 10更新了以下内容:

1.在您的主视图控制器中,将此代码添加到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)
}

1.创建助手函数以将滑块输出打印到viewDidLayoutSubviews()下面

func rangeSliderValueChanged() { //rangeSlider: RangeSlider
    print("Range slider value changed: (rangeSlider.lowerValue) (rangeSlider.upperValue) ")//((rangeSlider.lowerValue) (rangeSlider.upperValue))
}

1.创建RangeSlider.swft文件,并添加如下内容:

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
  }
}

1.接下来添加拇指层子类文件RangeSliderThumbLayer.swft,并添加如下内容:

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()
    }
  }
 }
}

1.最后添加轨迹层子类文件RangeSliderTrackLayer.wift,并添加以下内容:

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)
   }
  }
 }

构建、运行和获取:

6kkfgxo0

6kkfgxo02#

更新:

我看不出来,因为它全是白色的。因此,解决方案不使用任何其他框架并坚持使用此框架-您需要为所有组件设置所有视图,然后它将显示得很好:

我曾尝试在SWIFT中导入它,就像我以前在Objective-C代码中使用它一样,但没有任何运气。如果我正确地设置了所有内容并将其添加到viewDidLoad()viewDidAppear()中,则不会显示任何内容。不过,有一件事值得一提--当我进入查看调试层次结构时,滑块实际上*就在画布上:

但它只是没有使用我在将其添加到视图之前设置的所有颜色进行渲染。郑重声明--这是我使用的代码:

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()
}

使用this question中提到的将UIView捕获为UIImage的方法:

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编写的,因此您甚至不需要桥接头。

z5btuh9x

z5btuh9x3#

试试这个代码:

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)
}
nkhmeac6

nkhmeac64#

我使用: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)

要设置下标签和上标签的动画,请执行以下操作。

这个很适合我,而且是斯威夫特的。试试看..。

相关问题