في
المقالة الأخيرة ، نظرنا في العمل مع 3DTouch على iPhone. الآن يبقى لإكمال بضع ضربات وإنهاء طلبنا.

كما قلت ، الوظيفة الرئيسية جاهزة ، هناك تحسينات فقط:
- عند الوصول إلى القيمة القصوى ، أريد أن تعمل استجابة الاهتزاز كما هو الحال في مقال التعليقات اللمسية على iPhone 6s
- يحدث تحديث القيم في UILabel بسرعة كبيرة ، (أعتقد أنك لاحظت ذلك عند الاختبار) لذا تحتاج إلى إضافة بعض السلاسة.
- يجب أن تظهر دائرة شبه شفافة عند نقطة الضغط. يجب أن يزيد قطرها مع زيادة الضغط وانخفاض مع انخفاض الضغط
أول نقطتين لا يمكنني عرضهما باستخدام لقطات الشاشة أو باستخدام صور
متحركة . لذلك ، قم بإجراء الإضافات الموضحة أدناه وتحقق منها بنفسك على أجهزتك. وهنا سأوضح النقطة الثالثة. ولكن دعنا نقوم بالوظائف الإضافية معًا.
ردود فعل الاهتزاز
نستورد إطار عمل
AudioToolbox قبل إعلان فئة
ViewController ، ونضيف أيضًا خاصية
isPlaySound لاستبعاد
الاستجابة المتكررة
لاستجابة الاهتزاز.
import UIKit import AudioToolbox class ViewController: UIViewController { @IBOutlet weak var scaleView: ScaleView! @IBOutlet weak var forceLabel: UILabel! @IBOutlet weak var grammLabel: UILabel! var isPlaySound = true ...
بعد ذلك ، قم بإجراء تغييرات على طريقة
اللمسات المنقولة (: :) بحيث تبدو كما يلي:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) if #available(iOS 9.0, *) { if traitCollection.forceTouchCapability == UIForceTouchCapability.available { if touch.force >= touch.maximumPossibleForce { forceLabel.text = "100%+ force" grammLabel.text = "385 " if isPlaySound { // // 1 AudioServicesPlaySystemSound(1519) isPlaySound = false // 2 } } else { let force = (touch.force / touch.maximumPossibleForce) * 100 let grams = force * 385 / 100 let roundGrams = Int(grams) isPlaySound = true // // 3 forceLabel.text = "\(Int(force))% force" grammLabel.text = "\(roundGrams) " } } } } }
لا شيء معقد - عند تشغيل تطبيق iOS ، وفي هذه الحالة ، عند تهيئة
ViewController وإنشاء خاصية من فئة
isPlaySound ، نقوم بتمكين القدرة على تشغيل الأصوات - بما في ذلك استجابات الاهتزاز. عند الوصول إلى أقصى ضغط
، يتم فحص
isPlaySound (1) وإذا كان
صحيحًا ، يتم تنفيذ الاهتزاز ويتم تشغيل الحظر (2) على تشغيل الاهتزاز على الفور. يتم رفع هذا الحظر (3) إذا أصبحت قوة الضغط أقل من أقصى قيمة ممكنة.
تحديث سلس
الآن عن النعومة. تأتي تحديثات الملصقات بسرعة كبيرة ، مع سرعة استجابة
اللمسات المنقولة (: :) ، وهذه عدة مئات من العمليات في الثانية. لتقليل معدل تحديث التسمية ، أضفت خاصية
لفئة ViewController isUpdate وقمت بتعيين
مراقبين خاصية
didSet .
var isUpdate = true { didSet { if isUpdate == false { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { self.isUpdate = oldValue } } } }
جوهر مثل هذا البناء هو أنه بمجرد تعيين هذه الخاصية إلى false ، فإنها تعود إلى true بعد
0.01 ثانية. وفقًا لذلك ، عند كتابة نص إلى
UILabel ، سنقوم بتعيين قيمة خاصية
isUpdate إلى
false ولن نسمح بتحديث التسميات حتى تصبح
حقيقة . لذلك ، سيتم تحديث السجلات معنا أكثر من مرة واحدة كل مائة من الثانية.
في
اللمسات المنقولة (: :) الطريقة ، في الفرع حيث نعرض النسبة المئوية للقوة والوزن بالجرام ، قم بتغيير الكود كما يلي:
if isUpdate { forceLabel.text = "\(Int(force))% force" grammLabel.text = "\(roundGrams) " isUpdate = false }
سيكون هذا كافيًا لإضفاء السلاسة عند تحديث الملصقات
التصور باللمس
أولاً ، دعنا ننشئ
UIView ونجعلها شفافة ومستديرة. للقيام بذلك ، قم بإضافة خاصية من فئة
ViewController وقم بإجراء الإعدادات الأولية في طريقة
viewDidLoad () let cicrcleView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) // View 80 80 override func viewDidLoad() { super.viewDidLoad() forceLabel.text = "0% force" grammLabel.text = "0 " cicrcleView.layer.cornerRadius = 40 // View - cicrcleView.alpha = 0.6 // 60% cicrcleView.backgroundColor = UIColor.red }
هناك خاصية ، لها
عرض ، ولكن في أي نقطة يجب إضافتها إلى الشاشة؟ من المنطقي أن تبدأ في اللمس. في
ViewController تحتاج إلى إضافة طريقة
touchesBegan (: :) override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view)
نختار أيضًا الأول من مجموعة اللمسات والعمل مع هذه اللمسة
- اضبط مركز دائرة العرض على نقطة اللمس
- أضف cicrcleView إلى الشاشة
في
اللمسات المنقولة (: :) الطريقة في الفرع حيث تتم معالجة النسب المئوية والوزن بالجرام ، أضف السطر:
cicrcleView.transform = CGAffineTransform.init(scaleX: CGFloat(1 + (grams / 5) / 20), y: CGFloat(1 + (grams / 5) / 20))
هنا نضع مصفوفة التحويل لزيادة حجم
cicrcleView في الارتفاع والعرض. القيم التي قمت بنقلها إلى هذه المصفوفة هي نتيجة اختيار القيم الأكثر ملاءمة. طريقة الاختيار "كزة". حتى تتمكن من التجربة واختيار القيم التي تناسبك.
وأخيرًا ، في نهاية اللمسة ، تحتاج إلى إلغاء التحويل لـ
cicrleView وإزالته من الشاشة. لدينا بالفعل طريقة يمكنك من خلالها حلها. في طريقة
اللمسات النهائية (: :) ، أضف سطرين:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = "0% force" grammLabel.text = "0 "
يبدو رمز
ViewController الكامل كما يلي:
import UIKit import AudioToolbox class ViewController: UIViewController { @IBOutlet weak var scaleView: ScaleView! @IBOutlet weak var forceLabel: UILabel! @IBOutlet weak var grammLabel: UILabel! var isPlaySound = true var isUpdate = true { didSet { if isUpdate == false { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { self.isUpdate = oldValue } } } } let cicrcleView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) override func viewDidLoad() { super.viewDidLoad() forceLabel.text = "0% force" grammLabel.text = "0 " cicrcleView.layer.cornerRadius = 40 cicrcleView.alpha = 0.6 cicrcleView.backgroundColor = UIColor.red } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) // 1 view.addSubview(cicrcleView) // 2 } } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) if #available(iOS 9.0, *) { if traitCollection.forceTouchCapability == UIForceTouchCapability.available { if touch.force >= touch.maximumPossibleForce { forceLabel.text = "100%+ force" grammLabel.text = "385 " if isPlaySound { AudioServicesPlaySystemSound(1519) isPlaySound = false } } else { let force = (touch.force / touch.maximumPossibleForce) * 100 let grams = force * 385 / 100 let roundGrams = Int(grams) isPlaySound = true if isUpdate { forceLabel.text = "\(Int(force))% force" grammLabel.text = "\(roundGrams) " isUpdate = false } cicrcleView.transform = CGAffineTransform.init(scaleX: CGFloat(1 + (grams / 5) / 20), y: CGFloat(1 + (grams / 5) / 20)) } } } } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = "0% force" grammLabel.text = "0 " cicrcleView.removeFromSuperview() cicrcleView.transform = .identity } }
رمز ملف
ScaleView :
import UIKit @IBDesignable class ScaleView: UIView { override func draw(_ rect: CGRect) { let context = UIGraphicsGetCurrentContext() context?.setStrokeColor(UIColor.red.cgColor) context?.setLineWidth(14.0) context?.addArc(center: CGPoint(x: 375 / 2, y: 375 / 2), radius: 375 / 2 - 14, startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true) context?.strokePath() context?.setLineWidth(1.0) context?.setStrokeColor(UIColor.lightGray.cgColor) context?.addArc(center: CGPoint(x: 375 / 2, y: 375 / 2), radius: 375 / 4 - 14, startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true) context?.strokePath() } }
ربط المشروع على
جيثب