1080P çözünürlükteki Windows Phone'ların gelmesi ile beraber uygulamalarda da ne gibi değişiklikler yapmak gerekiyor soruları akla gelmeye başladı. Acaba bugüne kadar geliştirdiğimiz ve 720P için optimize ettiğimiz uygulamalarda ne gibi değişiklikler yapmak gerekecek? İşte bu yazıda bu sorunun cevabını vereceğiz.

"Phablet" adı 5" ve üstü büyüklükteki cihazları tanımlanırken kullanılıyor. Buradaki karışıklıklardan biri aslında hem çözünürlüğün hem de fiziksel olarak cihazın büyümesi ve maalesef API'lar 720P için tasarlanmış uygulamaları kırmayacak şekilde tutulduğu için 1080P'yi algılamanın tek yolu cihazın fiziksel büyüklüğüne bakmak oluyor. Yani, 720P'ye kadar çözünürlüğe bakarken sonrası için cihaz boyutuna bakmak zorunda kalıyor. Yarın öbür gün 5"'den büyük ve 1080P çözünürlükten düşük çözünürlüklü telefon çıkarsa ne yapacağız bilmiyorum :) Sanırım bu seçenek hiç gerçekleşmeyeceği için hem Nokia hem Microsoft rahat durumdalar.

[C#]

namespace resolutions_sample.Helpers
{
    public enum Resolutions { WVGAWXGAHD720pHD1080p };

    public static class ResolutionHelper
    {
        static private Size _size;

        private static bool IsWvga
        {
            get
            {
                return App.Current.Host.Content.ScaleFactor == 100;
            }
        }

        private static bool IsWxga
        {
            get
            {
                return App.Current.Host.Content.ScaleFactor == 160;
            }
        }

        private static bool Is720p
        {
            get
            {
                //ScaleFactor 1080P ve 720P'de aynı döndüğü için Is1080P'de 
                PhysicalScreenResolution'a bakmak zorundayız.

                return (App.Current.Host.Content.ScaleFactor == 150 && !Is1080p);
            }
        }

        private static bool Is1080p
        {
            get
            {
                if (_size.Width == 0)
                {
                    try
                    {
                        _size = (Size)DeviceExtendedProperties
                                    .GetValue("PhysicalScreenResolution");
                    }
                    catch (Exception)
                    {
                        _size.Width = 0;
                    }
                }
                return _size.Width == 1080;
            }
        }

        public static Resolutions CurrentResolution
        {
            get
            {
                if (IsWvgareturn Resolutions.WVGA;
                else if (IsWxgareturn Resolutions.WXGA;
                else if (Is720preturn Resolutions.HD720p;
                else if (Is1080preturn Resolutions.HD1080p;
                else throw new InvalidOperationException("Bilinmeyen Çözünürlük");
            }
        }
    }
}

Yukarıdaki Helper sınıfı çözünürlük tespiti için kullanabileceğiniz en güncel yardımcı sınıf. Şu anda Windows Phone'da var olan tüm çözünürlükleri tespit edebiliyor. Kod içerisinde de görebileceğiniz üzere 1080P'ye gelene App.Current.Host.Content.ScaleFactor kadar namespace'ini kullanıyoruz. 1080P'ye geldiğimizde maalesef 720P ile aynı ScaleFactor döndüğü için bu noktadan sonra detection yapmak mümkün olmuyor. Bunun nedeni daha önce de bahsettiğim gibi var olan uygulamaları kırmamak ve aslında uygulamaların aynen çalışmaya devam etmesini sağlamak. İşletim sistemi kendi scaling'ini uygulayarak işe devam ediyor. Fakat tabi ki istisnalar söz konusu olabilir. Birincisi siz uygulamanızda scaling yerine yeni gelen pikselleri farklı işler için kullanmak isteyebilirsiniz. İkincisi ise içeriğiniz scale edilemeyen bitmap'lerden oluşuyor da olabilir. Bu her iki senaryoda da 1080P çözünürlüğü algılayıp ona göre aksyon almak anlamlı olacaktır.

1080P'yi algılamak için cihazın fiziksel ekran boyutuna bakmamız gerekiyor. Bunun için de "PhysicalScreenResolution"'ı DeviceExtendedProperties'dan istiyoruz. Buradan dönen çözünürlüğe göre artık kendi scalingimize karar verebiliriz. Yukarıdaki kodu çalışan örnek bir uygulama ile Github'a da attım. Nitekim yazı boyunca var olan tüm Helper'ları Github'daki örneklerde bulabilirsiniz.

Çözünürlüğü yakalamanın ötesinde gerçekten ekranın boyutunu da merak edebilirsiniz. Bunun için Dpi bilgilerini alarak gerekli hesaplamaları yapmak yeterli olacaktır. Böylece cihazın gerçek boyutunu da öğrenebilir ve ona göre layout'unuzu nasıl düzenleyeceğinize karar verebilirsiniz.

[C#]

namespace resolutions_sample.Helpers
{
    class ScreenSizeHelper
    {
        static private double _screenSize = -1.0f;
        static private double _screenDpiX = 0.0f;
        static private double _screenDpiY = 0.0f;
        static private Size _resolution;
        
        static public double CurrentScreenSize
        {
            get
            {
                // Büyük ekranlı cihaz simülasyonu için emülatörde şimdilik 720P kullanılabilir.
                if (Microsoft.Devices.Environment.DeviceType == 
                                                    Microsoft.Devices.DeviceType.Emulator)
                {
                    _screenSize = (App.Current.Host.Content.ScaleFactor == 150? 6.0f : 0.0f;
                }

                if (_screenSize == -1.0f)
                {
                    try
                    {
                        _screenDpiX = (double)DeviceExtendedProperties.GetValue("RawDpiX");
                        _screenDpiY = (double)DeviceExtendedProperties.GetValue("RawDpiY");
                        _resolution = (Size)DeviceExtendedProperties
                                                .GetValue("PhysicalScreenResolution");

                        _screenSize =
                            Math.Sqrt(Math.Pow(_resolution.Width / _screenDpiX2+
                                      Math.Pow(_resolution.Height / _screenDpiY2));
                    }
                    catch (Exception e)
                    {
                        _screenSize = 0;
                    }
                }

                return _screenSize;
            }
        }
    }
}

Yukarıdaki Helper'ın bir öncekinden tek farkı RawDpiX ve RawDpiY özelliklerini de alarak ekran boyutunu hesaplaması. Böylece hem istediğimiz gibi çözünürlük biliglerine hem de cihazın boyutuna ulaşmış oluyoruz.

Resimlerde dikkat edilmesi gerekenler...

Nokia'ya soracak olursanız :) "1080P için tüm resimlerinizi düzenleyin ve sadece onları kullanın" diyorlar. Zaten işletim sistemi daha düşük çözünürlükte resim göstermek isterse rahatlıkla büyüğü ufaltıp gösterebiliyor. Ama bu durum tabi ki özellikle düşük bellekli cihazların koca koca resimlerle uğraşması anlamına gelecek ki bu da pek süper bir manzara değil. Bu durumu engellemek için kullanabileceğiniz taktiklerden biri BitmapImage nesnelerinizin DecodePixelWidth özelliğini kullanmak.

[C#]

      //Büyük bir resmi düşük bellek kullanımı ile yüklemek.
      var bmp = new BitmapImage();

      //Decode işleminde kullanılacak yatay piksel sayısı.
      bmp.DecodePixelWidth = 100;

      bmp.UriSource = new Uri(@"Assets\AlignmentGrid.png"UriKind.Relative);
      IMG.Source = bmp;

Bu özelliği set ederek aslında Decode'in sonucunda almak istediğin genişliği vermiş oluyorsunuz ve tüm resmi decode edip sonrasında resize etmek yerine çok daha performanslı bir süreçten geçiyorsunuz. Ayrıca bellek kullanımı da sadece göstereceğiniz Bitmap boyutunda oluyor çünkü Image kontrolünde tüm resim gitmiyor.

Bir diğer seçenek de tabi ki çözünürlüğe göre ayrı ayrı resimler yüklemek ama öyle bir iş yükünün altına girmek de pek mümkün gözükmüyor. Yine de gelin şu ScaleFactor ve gerçek boyutlara bir göz atalım. Kafalar biraz karışacak :)

768p (WXGA) bir cihazda 100px genişliğinde bir UI kontrolü 1.6x ScaleFactor nedeniyle 160px olarak render edilir. Yani ekranda bu şekilde gözükür. O nedenle 100px'lik bir Image kontrolüne aslında 160px'lik resim load etmeniz gerekir de tamamen net bir görüntü elde edin. Diğer yandan 1080P cihazlarda ScaleFactor 1.5 olarak gelir ama :) gerçek scaling 2.25 şeklinde gerçekleşir. Bu garip durum daha önce bahsettiğimiz API'ların 720P gibi davranmalarından kaynaklanıyor. Yani özetle 1080P bir cihazda 100px'lik kontrol ekrana 225px olarak yansır. Eğer ki göstereceğiniz resimlerin çözünürlükten ve cihazdan bağımsız olarak hep aynı büyüklükte gözükmesini isterseniz işiniz biraz daha zor. 768p ve 1080p cihazların mantıksal, yani UI kontrollerine verilen boyutlarının arasındaki oranın 1.6/2.225=0.7111 olması gerekiyor ki her iki cihazda da fiziksel olarak gösterilen öğeler bire bir aynı büyüklükte olsun. 768p cihazdaki kontrol eğer 0.7111 oranın ufaltılırsa 1080p cihazda da aynı büyüklükte gözükecektir. Allah kolaylık versin :)

Splash Screen ne olacak?

Burada da Microsoft ve Nokia'nın tavsiyeleri birbirinden farklı :) Projelerde hala 720p Splash Screen dosyasını göreceksiniz ve 1080P cihazlarda söz konusu SplashScreen dosyaları resize edilecek. Bu tabi ki hafif blur'lu Splash Screen'ler anlamına geliyor. Profil olarak AppManifest dosyasına da 1080P'nin gelmediğini düşünürsek Microsoft bakış açısı ile 1080P aslında developer'lara tamamen transparent kalmalı. API'lar aynı ScaleFactor'ı döndürdüğü gibi Splash Screen de aynı kalmalı. Ama diğer yandan Nokia'nın tavsiyesi için 720P JPEG dosyasında 1080P çözünürlükte resmi çakmanız yönünde :) Doğal olarak 720P cihazlarda scale-down ile bu resimler düzgün şekilde gözükecek ve 1080P cihazlarda da herhangi bir scale-up olmadığı için o cihazlarda da netlik korunacak. Aslına bakarsanız varsayılan ayarlarda Splash Screen dosyaları 768x1280 şeklinde. Böyle bir splash screen maalesef ki 1080P cihazlarda ekranın üstünde siyah bir boşluk / bant bırakcaktır. Karar sizin.

Live Tile'larda birşeyler var mı?

Bir değişiklik yok :) Aslına bakarsanız 1080P cihazlarda Live Tile'lar diğer çözünürlüklerden daha ufak gözüküyor. Bunun nedeni ise normalde kolon olan Start Screen'in üç kolona çıkıyor olması. 1080P cihazlardaki üç kolon nedeniyle kolon başına düşen genişlik 720P'deki iki kolonda kolon başına düşenden daha düşük. O nedenle 1080P cihazlarda Live Tile'lar daha ufalıyor :)

Daha çok bellek gerekirse?

1080P cihazlarla uğraşırken doğal olarak büyük resimler, büyük videolar derken herşeyin büyüdüğünü göreceksiniz ve uygulamanızın bellek kullanımı da otomatik olarak artacak. Bu durumda normal sınırlardaki bellek limitleri canınızı sıkmaya başlayabilir. Bugün 1GB ve üstü belleğe sahip telefonlarda XAML uygulamaları için 300MB limiti var. Düşük bellekli telefonlarda ise bu limit 150MB'a düşüyor. Özellikle 1080P telefonlarda bu limitleri yükseltmek için AppManifest'te ek bir talepte bulunabiliyorsunuz. (Dikkat bu özellikle WP8 Update 3 ile geliyor)

[WMAppManifest.xml]

  <App xmlns="" ProductID="{476ed98e-af35-41b6-ba7e-6c1132242400}
" Title="resolutions_sample" RuntimeType="Silverlight" Version="1.0.0.0" 
Genre="apps.normal" Author="resolutions_sample author" Description="Sample description" 
Publisher="resolutions_sample" PublisherID="{6b07464a-f45a-40b4-9f9b-0c335cb1c38a}">
    <FunctionalCapabilities>
      <FunctionalCapability Name="ID_FUNCCAP_EXTEND_MEM"/>
    </FunctionalCapabilities>
    <IconPath IsRelative="true" IsResource="false">Assets\ApplicationIcon.png</IconPath>
    <Capabilities>
      <Capability Name="ID_CAP_NETWORKING"/>
      <Capability Name="ID_CAP_MEDIALIB_AUDIO"/>
      <Capability Name="ID_CAP_MEDIALIB_PLAYBACK"/>
      <Capability Name="ID_CAP_SENSORS"/>
      <Capability Name="ID_CAP_WEBBROWSERCOMPONENT"/>
    </Capabilities>

Yukarıdaki gibi "Capability" olarak ID_FUNCCAP_EXTEND_MEM özelliğini isterseniz artık uygulamanızı daha yüksek bellek limitleri atanacak. 1GB bellekli telefonlarda 380MB, 2GB bellekli telefonlarda ise 570MB hafıza kullanabileceksiniz. 1GB altı telefonlar içinse limit 180MB'a çıkacak. Ayrıca isterseniz ID_REQ_MEMORY_300 özelliğini de "Requirement" olarak kullanarak uygulamanızın 1GB altı bellekli telefonlara yüklenememesini de sağlayabilirsiniz. İnsanları süründürmekten iyidir :)

Son olarak hatırlatiyim, yazıdaki herşey Github'da örnek bir projede var ;) Görüşmek üzere.