Существуют различные способы решения этой проблемы.
Один вариант ... вместо рисования только красной пунктирной линии в качестве слоя фигуры, нарисуйте серую линию, красную пунктирную линию и зеленую полосу как 3 подслоя.
- Нижний слой: серая линия
- Средний слой: красная пунктирная линия
- Верхний слой: зеленая линия "bar"
Поскольку зеленая полоса будет покрывать красные точки и серую линию, каждая из них может охватывать всю ширину между левым краем ячейки и левым краем первой метки. Это означает, что единственная часть, которой нужно изменить размер, это слой зеленой полосы.
Вот пример кода:
class MyProgressBarView: UIView {
var progress: CGFloat = 0.0 {
didSet {
setNeedsLayout()
}
}
let greenBar = CAShapeLayer()
let grayBar = CAShapeLayer()
let redBar = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
layer.addSublayer(grayBar)
layer.addSublayer(redBar)
layer.addSublayer(greenBar)
redBar.strokeColor = UIColor.red.cgColor
redBar.lineWidth = 2
// passing an array with the values [2,3] sets a dash pattern that alternates between a 2-user-space-unit-long painted segment and a 3-user-space-unit-long unpainted segment
redBar.lineDashPattern = [2,3]
grayBar.strokeColor = UIColor.lightGray.cgColor
grayBar.lineWidth = 1
greenBar.strokeColor = UIColor.green.cgColor
}
override func layoutSubviews() {
super.layoutSubviews()
var path = CGMutablePath()
path.addLines(between: [CGPoint(x: 0, y: bounds.height * 0.5),
CGPoint(x: bounds.width, y: bounds.height * 0.5)])
grayBar.path = path
redBar.path = path
path = CGMutablePath()
// cell height may change, so set greenBar's height here
greenBar.lineWidth = bounds.height
path.addLines(between: [CGPoint(x: 0, y: bounds.height * 0.5),
CGPoint(x: bounds.width * progress, y: bounds.height * 0.5)])
greenBar.path = path
}
}
class ProgressCell: UITableViewCell {
@IBOutlet var val1Label: UILabel!
@IBOutlet var val2Label: UILabel!
@IBOutlet var progView: MyProgressBarView!
var val1: CGFloat = 0.0 {
didSet {
val1Label.text = "\(val1)"
// make sure we don't divide by Zero
progView.progress = val2 > 0 ? val1 / val2 : 0.0
}
}
var val2: CGFloat = 0.0 {
didSet {
val2Label.text = "$\(val2)M"
// make sure we don't divide by Zero
progView.progress = val2 > 0 ? val1 / val2 : 0.0
}
}
}
struct MyValues {
var v1: CGFloat = 0.0
var v2: CGFloat = 0.0
}
class ProgressTableViewController: UITableViewController {
var myData: [MyValues] = [
MyValues(v1: 50.0, v2: 250.0),
MyValues(v1: 80.0, v2: 250.0),
MyValues(v1: 105.0, v2: 250.0),
MyValues(v1: 127.0, v2: 250.0),
MyValues(v1: 93.0, v2: 250.0),
MyValues(v1: 80.0, v2: 250.0),
MyValues(v1: 205.0, v2: 250.0),
MyValues(v1: 177.0, v2: 250.0),
MyValues(v1: 245.0, v2: 250.0),
]
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ProgressCell", for: indexPath) as! ProgressCell
let d = myData[indexPath.row]
cell.val1 = d.v1
cell.val2 = d.v2
cell.selectionStyle = .none
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let c = tableView.cellForRow(at: indexPath) as? ProgressCell {
let d = myData[indexPath.row]
var v = d.v1 + 10.0
v = min(v, d.v2)
myData[indexPath.row].v1 = v
c.val1 = v
}
}
}
А вот источник Storyboard:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="jKi-p9-QPh">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Progress Table View Controller-->
<scene sceneID="XK3-bb-mGO">
<objects>
<tableViewController id="xPK-h1-D8d" customClass="ProgressTableViewController" customModule="scratchy" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="Ofl-mQ-aYH">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="ProgressCell" id="hIa-mP-rya" customClass="ProgressCell" customModule="scratchy" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hIa-mP-rya" id="fVi-sL-ouy">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1va-uW-uvw" customClass="MyProgressBarView" customModule="scratchy" customModuleProvider="target">
<rect key="frame" x="16" y="11" width="187" height="21.5"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="150" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UNh-No-HjD">
<rect key="frame" x="211" y="11" width="50" height="21.5"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="ziy-02-rwL"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="$30.45M" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aDM-ad-OT7">
<rect key="frame" x="269" y="11" width="90" height="21.5"/>
<constraints>
<constraint firstAttribute="width" constant="90" id="cMB-Uy-RTf"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="1va-uW-uvw" firstAttribute="leading" secondItem="fVi-sL-ouy" secondAttribute="leadingMargin" id="BVh-vs-fur"/>
<constraint firstItem="UNh-No-HjD" firstAttribute="leading" secondItem="1va-uW-uvw" secondAttribute="trailing" constant="8" id="Fh8-Nf-sU3"/>
<constraint firstAttribute="trailingMargin" secondItem="aDM-ad-OT7" secondAttribute="trailing" id="GC9-ua-CdP"/>
<constraint firstItem="1va-uW-uvw" firstAttribute="top" secondItem="fVi-sL-ouy" secondAttribute="topMargin" id="Mg5-6e-QBM"/>
<constraint firstItem="aDM-ad-OT7" firstAttribute="top" secondItem="fVi-sL-ouy" secondAttribute="topMargin" id="YCc-VG-5rv"/>
<constraint firstAttribute="bottomMargin" secondItem="UNh-No-HjD" secondAttribute="bottom" id="bJG-Mk-j6m"/>
<constraint firstItem="UNh-No-HjD" firstAttribute="top" secondItem="fVi-sL-ouy" secondAttribute="topMargin" id="eKv-UH-Opf"/>
<constraint firstItem="aDM-ad-OT7" firstAttribute="leading" secondItem="UNh-No-HjD" secondAttribute="trailing" constant="8" id="laQ-5R-RZa"/>
<constraint firstAttribute="bottomMargin" secondItem="1va-uW-uvw" secondAttribute="bottom" id="loG-KQ-7xC"/>
<constraint firstAttribute="bottomMargin" secondItem="aDM-ad-OT7" secondAttribute="bottom" id="wml-fK-ewt"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="progView" destination="1va-uW-uvw" id="Ips-T7-vZ5"/>
<outlet property="val1Label" destination="UNh-No-HjD" id="Gqe-bP-u0c"/>
<outlet property="val2Label" destination="aDM-ad-OT7" id="gMP-5N-FIb"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="xPK-h1-D8d" id="iaK-Nh-quP"/>
<outlet property="delegate" destination="xPK-h1-D8d" id="1qh-e9-C6l"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="Gie-Xj-DLT"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="9As-Tc-u8W" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="357.60000000000002" y="2048.7256371814096"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="k92-RW-oNV">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="jKi-p9-QPh" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="HPb-es-8az">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="xPK-h1-D8d" kind="relationship" relationship="rootViewController" id="QXa-oP-Nwz"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vwe-Vd-YNO" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-581.60000000000002" y="2048.7256371814096"/>
</scene>
</scenes>
</document>
Результат:
и, при повороте устройства, вы можете видеть, что оно автоматически обрабатывает изменение размера - никакого специального кода для этого :
Если вы добавите это в новый проект и запустите его, я также реализовал didSelectRowAt
- каждый раз, когда вы нажимаете на строку , это увеличит «левое значение» на 10.0
, так что вы можете видеть, как зеленая полоса динамически растет.