תמיכה במצלמה בכמה גורמי צורה

אפליקציות ל-Android פועלות ביותר גורמי צורה מאשר רק בטלפונים שמחזיקים במצב לאורך. עם ההשקה של ממשק חלונות למחשב, מסכים מחוברים ומכשירים מתקפלים, אפליקציית המצלמה צריכה להתאים את עצמה לגדלים דינמיים של חלונות, ליחסי גובה-רוחב משתנים ולחומרה חיצונית.

איור 1. דוגמה לאפליקציות מצלמה במסכים שונים.

למה הלוגיקה של הטלפון נכשלת

אפליקציות מצלמה מניחות הנחות שגורמות לכשלים קריטיים בסביבות עם כמה גורמי צורה.

כיוון טבעי

  • הנחה: הכיוון הטבעי של המכשיר ROTATION_0 הוא תמיד לאורך
  • בפועל: בטאבלטים, במסך הפנימי של חלק מהמכשירים המתקפלים ובמסכים של מחשבים שולחניים, ROTATION_0 הוא לרוב לרוחב
  • תוצאה: התצוגה המקדימה מסובבת ב-90 מעלות בצורה שגויה
איור 2. העינית של המצלמה לפני ואחרי שמחילים את הסיבוב הנכון.

יישור החיישן

  • הנחה: הצד הארוך של חיישן המצלמה מיושר עם הצד הארוך של המסך
  • מציאות: חלון שניתן לשינוי גודל יכול להיות ריבועי או לרוחב, בזמן שהחיישן נשאר קבוע (בדרך כלל 4:3)
  • תוצאה: תמונות מתוחות או מעוותות
איור 3. העינית של המצלמה לפני ואחרי החלת גורם קנה המידה הנכון.

דחיסות וגודל המסך

  • הנחה: הצפיפות והגודל של המסך לא משתנים בזמן הריצה
  • המצב בפועל: בסביבות של מחשבים, המשתמשים יכולים לשנות את הגודל של החלונות באופן חופשי
  • תוצאה: הפעלה מחדש של סשן המצלמה בכל אירוע גרירה משבשת את חוויית המשתמש ועלולה לגרום לקריסות

פתרון 1: שימוש בכוונות של המערכת

אם האפליקציה שלכם צריכה לצלם תמונה או סרטון, אבל לא נדרש ממשק מצלמה מותאם אישית, הדרך הכי טובה להתמודד עם גורמי צורה שונים היא להפעיל את מצלמת המערכת שהותקנה מראש במכשיר (ראו Camera intents).

שימוש ב-intent של המערכת מעביר את כל חוויית הצילום לאפליקציית המצלמה שפותחה על ידי יצרן הציוד המקורי (OEM) של המכשיר. הפתרון הזה מאפשר להעביר למיקור חוץ את המורכבות של תמיכה בגורמי צורה, כולל:

  • תמיכה מובנית בשינוי גודל ובסיבוב – אפליקציית המצלמה שמוגדרת כברירת מחדל בטלפון מתקפל או בטאבלט נבנית במפורש על ידי היצרן כדי לטפל בגיאומטריה הספציפית של המכשיר. האפליקציה מתוכננת להתנהג בצורה תקינה כשהמכשיר נפתח, מסובב או מועבר למצב ריבוי חלונות.

  • גישה לתכונות מתקדמות של החומרה – לאפליקציות מצלמה של יצרן הציוד המקורי יש גישה בלעדית לאלגוריתמים מותאמים לחומרה (מצב לילה, HDR, החלפה בין עדשות ספציפיות) שקשה או בלתי אפשרי לשכפל באופן ידני.

פתרון 2: שימוש ב-Jetpack CameraX

CameraX היא ספריית Jetpack שנוצרה כדי להקל על פיתוח אפליקציות מצלמה. ‫CameraX מודעת למחזור החיים ומכוונת למשטח. בניגוד ל-Camera2, שדורשת חישוב מחדש ידני של כיוון החיישן וגדלי המשטחים בכל פעם שמקפלים, מסובבים או משנים את הגודל של המכשיר, CameraX מטפלת אוטומטית בהגדרה מחדש של סשנים של מצלמה במהלך שינוי גודל של חלונות מרובים או כשמעבירים אפליקציה לתצוגה מחוברת, וכך מבטיחה שזרם התצוגה המקדימה יותאם בלי לגרום לגימגום או למתיחה.

רכיבים כמו PreviewView מנהלים בצורה חכמה את יחס הגובה-רוחב ואת סוגי קנה המידה במצבים שונים, כמו מעבר של מכשיר מתקפל ממסך חיצוני למסך פנימי. כך אפשר לתמוך במגוון רחב של חומרה באמצעות הטמעה עקבית אחת, במקום אוסף מורכב של מקרים פרטיים ספציפיים למכשיר.

כתיבה

ב-Jetpack Compose, משתמשים בספרייה הייעודית androidx.camera:camera-compose. הספרייה מספקת את הרכיב הקומפוזבילי CameraXViewfinder, שנועד לטפל בגיאומטריה המורכבת של שינוי גודל, סיבוב ויחסי גובה-רוחב במהלך מחזור החיים של Compose.

רכיב CameraXViewfinder מסיר את המקורות הנפוצים ביותר לשגיאות באפליקציות מצלמה:

  • המרת קואורדינטות אוטומטית – אחד החלקים הכי קשים בפיתוח אפליקציית מצלמה הוא מיפוי של הקשה של משתמש (קואורדינטות x, y במסך) למערכת הקואורדינטות של חיישן המצלמה (0-1, 0-1 מסובב) לצורך מיקוד ומדידה. ‫CameraXViewfinder מספק CoordinateTransformer שמטפל במתמטיקה באופן אוטומטי, גם כשמשנים את גודל החלון או כשמקפלים את המכשיר.
  • התנהגות נכונה של פריסה – בניגוד ל-SurfaceView או ל-TextureView,‏ CameraXViewfinder פועל בצורה נכונה עם הסדר של שכבות ה-Z ב-Compose. אתם יכולים להוסיף שכבת-על של רכיבי ממשק משתמש (טבעות מיקוד, אמצעי בקרה) או להחיל משנים (פינות מעוגלות, אנימציות) בלי להציג ארטיפקטים של רינדור.
  • שינוי גודל ויחס גובה-רוחב: CameraXViewfinder מטפל באופן פנימי בלוגיקה של חיתוך במרכז לעומת התאמה למרכז, כדי לוודא שהתצוגה המקדימה לא תימתח כשמשנים את הגודל של חלון האפליקציה ליחסי גובה-רוחב לא סטנדרטיים (לדוגמה, מצב מסך מפוצל או מצב חלונות במחשב).

צפיות

באפליקציות מבוססות-תצוגה, משתמשים ב-PreviewView או ב-ViewFinderView. אם אתם משתמשים ישירות ב-SurfaceView או ב-TextureView, אתם צריכים לחשב את יחס הגובה-רוחב ולהחיל בעצמכם את מטריצת הטרנספורמציה הנכונה.

פתרון 3: טיפול דינמי בכיוון ובשינוי הגודל

כשמשתמשים ישירות בממשקי API של פלטפורמות, חשוב לזכור את סיבוב המכשיר, את ההפעלה מחדש של הפעילות ואת יחס הגובה-רוחב.

הפסקת השימוש בסיבוב המכשיר

אל תסתמכו רק על Display#getRotation() או על כיוון החיישן הפיזי כדי לקבוע את פריסת ממשק המשתמש.

  • שימוש במדדי חלון – כדי לקבוע את הפריסה (ממשק משתמש לרוחב או לאורך), משווים את הרוחב והגובה של חלון האפליקציה באמצעות WindowManager#getCurrentWindowMetrics().
  • התעלמות מכיוון טבעי – יכול להיות שהאפליקציה מוצגת בחלון בצורת לאורך במסך לרוחב. הכיוון של המכשיר לא רלוונטי לגבולות של ממשק המשתמש.

איך להימנע מהפעלה מחדש של פעילות

ההתנהגות שמוגדרת כברירת מחדל ב-Android היא השמדה של הפעילות באפליקציה בשינויים בהגדרות (כמו שינוי גודל החלון). באפליקציות של מצלמות, הבעיה הזו מופיעה כהבהוב במסך או כניתוק במהלך שיחות וידאו.

יחס גובה-רוחב וחיתוך

בעיה נפוצה במכשירים מתקפלים ובחלונות במחשב היא מתיחה של התצוגה המקדימה, שבה תמונה ממצלמה ביחס של 4:3 נמתחת בכוח לחלון ביחס של 16:9 או 1:1.

  • לא למתוח – אף פעם לא מכריחים את מאגר הנתונים הזמני של המצלמה להתאים בדיוק לגבולות התצוגה אם יחסי הגובה-רוחב של התצוגה המקדימה והחלון שונים.
  • חיתוך במרכז (מומלץ): שינוי קנה המידה של התצוגה המקדימה כך שתמלא את המימד הקצר ביותר של החלון וחיתוך של החלקים העודפים. כך מוודאים שהנושא לא מעוות וממלא את הפריים.
  • התאמה למרכז (אפשרות חלופית): אם חשוב להציג את כל שדה הראייה (לדוגמה, כשסורקים מסמך), התצוגה המקדימה תופיע בפורמט Letterbox בתוך החלון.
  • התאמה למרכז (אפשרות חלופית): אם חשוב להציג את כל שדה הראייה (לדוגמה, כשסורקים מסמך), התצוגה המקדימה תופיע בפורמט Letterbox בתוך החלון.

בונוס: תמיכה בחוויות שימוש שמותאמות למכשירים מתקפלים

מכשירים מתקפלים הם לא רק טלפונים שאפשר לכופף, הם מציעים מצבי חומרה ייחודיים שיכולים לשפר באופן משמעותי את האופן שבו המשתמשים מצלמים תמונות וסרטונים. במקום להתייחס לקיפול כבעיה שצריך לפתור, אפשר להשתמש בו כדי ליצור תכונות שלא אפשריות במכשירים לא מתקפלים.

מצב שולחני (צילום בהפעלה קולית)

מצב שולחני מאפשר למשתמשים לקפל את המכשיר לחצי ולהניח אותו על משטח כדי לבצע שיחות וידאו ארוכות, לצלם תמונות בטכניקת Time-lapse ולצלם תמונות בלילה בחשיפה ארוכה.

איור 5. אפליקציית תקשורת במצב שולחן: העינית של המצלמה נמצאת בחלק העליון של הציר, והפקדים בחלק התחתון.

מצב מסך אחורי (תמונות סלפי באיכות גבוהה)

  • במכשירים מתקפלים, המצלמות האחוריות הן בדרך כלל באיכות גבוהה יותר מהמצלמות שפונות אל המשתמש. מצב מסך אחורי מאפשר למשתמש לפתוח את המכשיר ולהפוך אותו, כך שהמסך הקטן שבחזית משמש כעינית בזמן אמת למצלמה האחורית הראשית.
  • מצב הצילום במסך האחורי מאפשר לצלם סלפי באיכות של 50MP ומעלה, תמונות קבוצתיות רחבות במיוחד וולוגים באיכות גבוהה בלי לשאת ציוד נוסף.

מצב מסך מפוצל (תצוגה מקדימה של התכונה)

  • במצב Dual Screen אפשר להציג את התצוגה המקדימה של המצלמה גם במסך הפנימי וגם במסך החיצוני בו-זמנית. האפשרות הזו מושלמת לצילום אנשים: האנשים שמצולמים יכולים לראות את עצמם במסך החיצוני ולשנות את התנוחה שלהם בזמן שאתם ממסגרים את התמונה במסך הפנימי.
  • בניגוד למצב של מסך חיצוני (שמעביר את כל האפליקציה), במצב של מסך מפוצל נוצר חלון משני של המצגת במסך החיצוני.
איור 5. אפליקציית מצלמה במצב מסך מפוצל.