मुख्य बिंदु
Pinch-to-Zoom (चुटकी) एक मल्टी-टच जेस्चर है जो प्रदर्शित सामग्री के स्केल को बदलने के लिए दो उंगलियों का उपयोग करता है। उंगलियों को पास लाने पर (pinch close), स्केल घटता है; उन्हें फैलाने पर (pinch open), बढ़ता है। जेस्चर निरंतर है: सिस्टम वास्तविक समय में उंगलियों के बीच की दूरी को ट्रैक करता है और मध्यवर्ती घटनाएँ उत्पन्न करता है, जिससे एप्लिकेशन सुचारू रूप से स्केल अपडेट कर सकता है।
जेस्चर की यांत्रिकी दो स्पर्श बिंदुओं के बीच की दूरी की गणना पर आधारित है। iOS और Android यूक्लिडियन दूरी का उपयोग करते हैं: sqrt((x2−x1)² + (y2−y1)²)। वर्तमान स्केल की गणना वर्तमान दूरी और प्रारंभिक दूरी के अनुपात के रूप में की जाती है। यदि प्रारंभिक दूरी 100px थी और 150px हो जाती है — स्केल = 1.5 (50% वृद्धि)। iOS पिछली स्थिति (डेल्टा) के सापेक्ष स्केल पास करता है, Android ScaleGestureDetector के माध्यम से संचित स्केल पास करता है।
Google Material Design Guidelines के अनुसार, Pinch-to-Zoom उन एप्लिकेशन के लिए अनिवार्य है जो छवियाँ, मानचित्र या दस्तावेज़ प्रदर्शित करते हैं। IT Sectr में, हम सभी प्रोजेक्ट्स में UIPinchGestureRecognizer और ScaleGestureDetector के साथ इस जेस्चर को लागू करते हैं जो दृश्य सामग्री के साथ काम करते हैं — गैलरी से लेकर इमेज एडिटर तक।
UIPinchGestureRecognizer पिंच जेस्चर को पहचानने के लिए UIGestureRecognizer का एक निरंतर उपवर्ग है। डिस्क्रीट रिकॉग्नाइज़र (UITapGestureRecognizer) के विपरीत, यह घटनाओं का एक क्रम उत्पन्न करता है: .began (उंगलियाँ स्क्रीन को छूती हैं), .changed (उंगलियों की प्रत्येक गति), .ended (उंगलियाँ उठा ली जाती हैं)।
मुख्य गुण: scale (CGFloat) — जेस्चर की शुरुआत के बाद से उंगलियों के बीच की दूरी में सापेक्ष परिवर्तन; velocity (CGFloat) — प्रति सेकंड स्केल परिवर्तन की दर। प्रारंभिक स्केल = 1.0। उंगलियों को फैलाने पर, स्केल बढ़ता है (1.0 → 1.5 → 2.0); पास लाने पर, घटता है (1.0 → 0.8 → 0.5)। velocity गुण जड़ता के लिए उपयोग किया जाता है: .ended के बाद, आप मंदी के साथ निरंतर स्केलिंग को एनिमेट कर सकते हैं।
UIPinchGestureRecognizer अन्य रिकॉग्नाइज़र (जैसे, मानचित्र पर pan + pinch) के साथ एक साथ पहचान के लिए delegate गुण का समर्थन करता है। gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) विधि true लौटाती है, और दोनों जेस्चर समानांतर में काम करते हैं। Apple व्यक्तिगत तत्वों के बजाय कंटेनर व्यू पर UIPinchGestureRecognizer जोड़ने की सलाह देता है — इससे स्केलिंग पिवट बिंदु की गणना सरल हो जाती है।
ScaleGestureDetector Android Support Library (android.view) का एक वर्ग है जो मल्टी-टच स्केलिंग को पहचानने के लिए डिज़ाइन किया गया है। GestureDetector.onFling के विपरीत, ScaleGestureDetector विशेष रूप से दो-उंगली ज़ूम के लिए बनाया गया है और स्वचालित रूप से focusX, focusY (उंगलियों के बीच केंद्र बिंदु) और scaleFactor (पिछली घटना से स्केल डेल्टा) की गणना करता है।
ScaleGestureDetector OnScaleGestureListener इंटरफ़ेस के माध्यम से तीन विधियों के साथ काम करता है: onScaleBegin(detector) (.began के अनुरूप), onScale(detector) (.changed के अनुरूप, boolean लौटाता है — true यदि स्केल स्वीकार किया जाता है), onScaleEnd(detector) (.ended के अनुरूप)। गुण: scaleFactor — पिछली घटना के सापेक्ष स्केल गुणक (~1.01 धीमी फैलाव के लिए), focusX/focusY — उंगलियों के बीच केंद्र बिंदु के निर्देशांक।
View पर स्केलिंग लागू करने के लिए, आमतौर पर Matrix का उपयोग किया जाता है: view.imageMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY)। Matrix परिवर्तनों के संचय का समर्थन करता है — प्रत्येक postScale कॉल मौजूदा परिवर्तन में एक नया परिवर्तन जोड़ता है। यह याद रखना महत्वपूर्ण है: ScaleGestureDetector न्यूनतम/अधिकतम स्केल को सीमित नहीं करता है — यह डेवलपर की जिम्मेदारी है। IT Sectr में, हम कस्टम स्केल सीमाओं (0.5–3.0) और सीमा से अधिक होने पर रिटर्न एनिमेशन के साथ ScaleGestureDetector का उपयोग करते हैं।
Pinch-to-Zoom को लागू करते समय, न्यूनतम और अधिकतम स्केल को सीमित करना अत्यंत महत्वपूर्ण है — इसके बिना, उपयोगकर्ता अनंत तक ज़ूम इन या अदृश्यता तक ज़ूम आउट कर सकता है। मानक मान: min = 0.5 (मूल आकार का 50%), max = 3.0 (300%)। iOS पर, सीमा क्लैम्प के माध्यम से की जाती है: newScale = min(max(currentScale * gesture.scale, minScale), maxScale)। Android पर — postScale के बाद जाँच के माध्यम से।
पिवट बिंदु उंगलियों के बीच का केंद्र बिंदु है, जिसके सापेक्ष स्केलिंग की जाती है। iOS स्वचालित रूप से दो स्पर्शों के केंद्रक की गणना करता है और इसे location(in:) के माध्यम से पास करता है — डेवलपर को मैन्युअल रूप से पिवट की गणना करने की आवश्यकता नहीं है। Android ScaleGestureDetector में focusX/focusY प्रदान करता है, लेकिन Matrix के माध्यम से लागू करते समय, पिवट को postScale(scaleFactor, scaleFactor, focusX, focusY) में तीसरे और चौथे तर्क के रूप में पास किया जाता है। पिवट बिंदु के बिना, स्केलिंग ऊपरी-बाएँ कोने (0,0) के सापेक्ष की जाएगी, जिससे ज़ूम के दौरान सामग्री खिसक जाती है।
IT Sectr के अनुभव के अनुसार, सही पिवट बिंदु गणना Pinch-to-Zoom लागू करते समय बग का सबसे सामान्य स्रोत है। 90% मामलों में, GestureRecognizer और ScaleGestureDetector के अंतर्निहित निर्देशांक का उपयोग करना पर्याप्त है — मैन्युअल रूप से पिवट की गणना करने की आवश्यकता नहीं है। यदि स्केलिंग के दौरान सामग्री खिसकती है, तो जाँचें कि क्या आप focusX/focusY को matrix.postScale() में पास कर रहे हैं।
जेस्चर समाप्त होने के बाद सुचारू UX के लिए, आप जड़ता जोड़ सकते हैं: iOS पर — UIView.animate और स्प्रिंग पैरामीटर के साथ UIPinchGestureRecognizer से velocity का उपयोग करें; Android पर — OverScroller या ValueAnimator। जड़ता को min/max स्केल सीमाओं से अधिक नहीं होना चाहिए — सीमा से अधिक होने पर स्प्रिंग-रिटर्न एनिमेशन के साथ अंतिम मान काट दिया जाता है।
0.5 से 3.0 तक स्केल सीमा के साथ UIImageView पर UIPinchGestureRecognizer जोड़ता है। संचित स्केल संरक्षण के साथ न्यूनतम कार्यान्वयन दिखाता है।
import UIKit
class ZoomableImageViewController: UIViewController {
@IBOutlet private var imageView: UIImageView!
private var currentScale: CGFloat = 1.0
private let minScale: CGFloat = 0.5
private let maxScale: CGFloat = 3.0
override func viewDidLoad() {
super.viewDidLoad()
let pinch = UIPinchGestureRecognizer(
target: self,
action: #selector(handlePinch(_:))
)
imageView.addGestureRecognizer(pinch)
imageView.isUserInteractionEnabled = true
}
@objc private func handlePinch(_: UIPinchGestureRecognizer) {
if gestureRecognizer.state == .began
|| gestureRecognizer.state == .changed {
let newScale = currentScale * gestureRecognizer.scale
imageView.transform = CGAffineTransform(
scaleX: min(max(newScale, minScale), maxScale),
y: min(max(newScale, minScale), maxScale)
)
}
if gestureRecognizer.state == .ended {
currentScale = min(max(
currentScale * gestureRecognizer.scale,
minScale
), maxScale)
gestureRecognizer.scale = 1.0
}
}
}
तर्क: .began/.changed में, क्लैम्प के साथ CGAffineTransform के माध्यम से स्केल लागू किया जाता है। .ended में, स्केल 1.0 पर रीसेट होता है और संचित मान currentScale में संग्रहीत होता है। यह बार-बार जेस्चर के दौरान स्केल ड्रिफ्ट को रोकता है — प्रत्येक नया जेस्चर वर्तमान स्थिति से शुरू होता है। छवियों के लिए, CGAffineTransform के बजाय minimumZoomScale/maximumZoomScale के साथ UIScrollView की सिफारिश की जाती है।
Matrix के साथ ScaleGestureDetector के माध्यम से ImageView स्केलिंग लागू करता है। सही पिवट बिंदु हैंडलिंग और स्केल सीमा दिखाता है।
import android.content.Context
import android.graphics.Matrix
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.widget.ImageView
class PinchZoomImageView(context: Context) : ImageView(context) {
private val matrix = Matrix()
private var currentScale = 1f
private val minScale = 0.5f
private val maxScale = 3.0f
private val scaleDetector =
ScaleGestureDetector(context, ScaleListener())
private inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
override fun onScale(detector: ScaleGestureDetector): Boolean {
currentScale = (currentScale * detector.scaleFactor)
.coerceIn(minScale, maxScale)
matrix.postScale(
currentScale,
currentScale,
detector.focusX,
detector.focusY
)
imageMatrix = matrix
return true
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
scaleDetector.onTouchEvent(event)
return true
}
}
कस्टम ImageView onTouchEvent को ओवरराइड करता है, ScaleGestureDetector को इवेंट पास करता है। OnScaleListener.onScale() प्रत्येक उंगली गति पर कॉल किया जाता है। detector.scaleFactor डेल्टा है (धीमी फैलाव के लिए 1.01)। currentScale क्लैम्पिंग के लिए coerceIn के साथ संचित होता है। focusX/focusY — उंगलियों के बीच केंद्र बिंदु, सही पिवट स्केलिंग के लिए postScale को पास किया जाता है।
UIScrollView में अपने डेलिगेट के माध्यम से अंतर्निहित Pinch-to-Zoom समर्थन है। यह छवियों और दस्तावेज़ों के लिए पसंदीदा दृष्टिकोण है — ScrollView स्वचालित रूप से स्केल, जड़ता और स्क्रॉलिंग का प्रबंधन करता है।
class ScrollableImageViewController: UIViewController,
UIScrollViewDelegate {
@IBOutlet private var scrollView: UIScrollView!
@IBOutlet private var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.minimumZoomScale = 0.5
scrollView.maximumZoomScale = 3.0
scrollView.delegate = self
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
}
UIScrollView स्वचालित रूप से UIPinchGestureRecognizer बनाता है, CALayer परिवर्तन के माध्यम से स्केलिंग का प्रबंधन करता है, और सीमाओं से अधिक होने पर बाउंस प्रभाव जोड़ता है। कोड min/maxZoomScale सेट करने और viewForZooming लौटाने तक सीमित हो जाता है। IT Sectr में, हम सभी फुल-स्क्रीन छवियों के लिए UIScrollView का उपयोग करते हैं — यह UIPinchGestureRecognizer के माध्यम से मैन्युअल कार्यान्वयन की तुलना में कोड वॉल्यूम को 5 गुना कम करता है।
अक्सर पूछे जाने वाले प्रश्न
टच स्क्रीन पर, पिंच उनके बीच की दूरी ट्रैकिंग के साथ दो उंगलियों का उपयोग करता है। MacBook ट्रैकपैड पर, ज़ूम UIPinchGestureRecognizer के माध्यम से समान अवस्थाओं (.began → .changed → .ended) के साथ लागू किया जाता है, लेकिन स्पर्श स्रोत Force Touch ट्रैकपैड है, कैपेसिटिव स्क्रीन नहीं। API समान है, यांत्रिकी समान है।
iOS पर: UIPinchGestureRecognizer से स्केल प्राप्त करने के बाद, currentScale से गुणा करें और clamp(min: 0.5, max: 3.0) लागू करें। Android पर: matrix.postScale() से पहले coerceIn(minScale, maxScale) का उपयोग करें। UIScrollView में — minimumZoomScale और maximumZoomScale गुणों के माध्यम से। सीमा के बिना, स्केल अनंत या शून्य तक जा सकता है।
नहीं, पिंच के लिए कम से कम दो उंगलियाँ आवश्यक हैं। एक-उंगली ज़ूम (डबल-टैप + ऊपर/नीचे खींचना) के लिए, UIPanGestureRecognizer या GestureDetector.onScroll के माध्यम से कस्टम कार्यान्वयन की आवश्यकता होती है। यह अलग तर्क वाला एक अलग जेस्चर है — आमतौर पर कैमरा या मानचित्र में ज़ूम के लिए उपयोग किया जाता है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें