اہم نکات
Pinch-to-Zoom (چٹکی) ایک ملٹی ٹچ جیسچر ہے جو ظاہر کردہ مواد کے پیمانے کو تبدیل کرنے کے لیے دو انگلیاں استعمال کرتا ہے۔ انگلیوں کو قریب لانے پر (pinch close)، پیمانہ کم ہوتا ہے؛ پھیلانے پر (pinch open)، بڑھتا ہے۔ جیسچر مسلسل ہے: سسٹم حقیقی وقت میں انگلیوں کے درمیان فاصلے کو ٹریک کرتا ہے اور درمیانی واقعات پیدا کرتا ہے، جس سے ایپلی کیشن آسانی سے پیمانہ اپ ڈیٹ کر سکتی ہے۔
جیسچر کا میکینکس دو ٹچ پوائنٹس کے درمیان فاصلے کے حساب پر مبنی ہے۔ iOS اور Android Euclidean فاصلہ استعمال کرتے ہیں: 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 کو نافذ کرتے وقت، کم سے کم اور زیادہ سے زیادہ پیمانہ محدود کرنا انتہائی اہم ہے — اس کے بغیر، صارف لامحدود طور پر زوم ان یا غائب ہونے تک زوم آؤٹ کر سکتا ہے۔ معیاری اقدار: کم سے کم = 0.5 (اصل سائز کا 50%)، زیادہ سے زیادہ = 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() میں منتقل کر رہے ہیں۔
جیسچر ختم ہونے کے بعد ہموار یوزر تجربہ کے لیے، آپ جڑت شامل کر سکتے ہیں: iOS پر — UIView.animate اور اسپرنگ پیرامیٹرز کے ساتھ UIPinchGestureRecognizer سے velocity استعمال کریں؛ Android پر — OverScroller یا ValueAnimator۔ جڑت کو کم سے کم/زیادہ سے زیادہ پیمانہ حدود سے تجاوز نہیں کرنا چاہیے — حد سے تجاوز کرنے پر اسپرنگ واپسی اینیمیشن کے ساتھ حتمی قدر کاٹ دی جاتی ہے۔
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 ٹریک پیڈ پر، زوم ایک جیسی حالتوں (.began → .changed → .ended) کے ساتھ UIPinchGestureRecognizer کے ذریعے نافذ کیا جاتا ہے، لیکن ٹچ کا ذریعہ 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 ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں