Xamarin ile Tasarım Desenleri Sayesinde Mobilde Profiller Arası Gezinme

Selamlar;

Xamarin_Blue_Logo

Bugün Xamarin ile profillerin gezildiği bir android uygulamasını hep beraber kodlayacağız.

Öncelikle aşağıdaki gibi “JobProfile” adında boş bir Android uygulaması açılır.

blank_Project

Resources/layout/Main.axml: Aşağıda görüldüğü gibi UI kısmının tasarlandığı alan burasıdır.

main       screen

Buradan “Source” tabına geçildiğin de aşağıdaki gibi bir koda erişilir:

Öncelikle “LinerLayout”‘u “RelativeLayout” olarak değiştirip, ilgili button kaldırılır. Buna şu an ihtiyaç yoktur.

Linear layout” nesneleri tamamen yatay veya dikey olarak konumlandırmak için kullanılır. Yani tüm nesneler tek bir yönde kullanılabilir. “Relative Layout” ise, içine aldığı görselleri konumlandırmak için kullanılır. Yani içine eklenen görsel öğeyi bir veya birkaç var olan öğeyi referans alarak dizer. Daha da detaylı anlatılmak istenir ise, yeni eklenecek bir nesne var olan bir nesneyi referans alarak, sen bu nesnenin sağına veya soluna geç denebilir. Relative Layout’un içine eklenen ilk öğe öntanımlı olarak ekranın en üst sol bölümüne konumlanır.

Öncelikle yazılacak mobil uygulama ile alakalı senaryoyu belirleyelim. Çeşitli mesleklerdeki kişilerin ünvanları, profil resimleri ve açıklamaları ileri ve geri buttonlarına basılarak sıra ile görüntülenecek. Son kayıda gelinince ileri buttonu, ve ilk kayıtda da  geri buttonu pasif hale getirilecek. Öncelikle ekran tasarımını aşağıdaki videoda görüldüğü gibi yapalım.

İlk olarak ileri ve geri buttonlarını yerleştirelim. Main.axml’de “Design” tabına geçilip toolbardan ButtonAdd bir button ekrana sürüklenir. Öncelikle aşağıda görüldüğü gibi buttonun ekranın altına “layout_alignParentButton=true” ile yapışması sağlanır. Ekranın soluna yapışması için “layout_alignParentLeft=true” atanır. Üzerindeki yazı “text=Prev” ile atanıp “id=btnPrev” şeklinde değiştirilir.

ButtonPosition

2.Button aşağıda görüldüğü gibi “Prev” buttonun sağına gelecek şekilde sürüklenir. Sürüklenilecek kenar mavi ile otomatik sistem tarafından işaretlenir.

2Button  2. Butttonun ekranın altında olması için “alignParentButton=true” değeri atanır. “text=Next” yapılır. “layout_toRightOf” temizlenir. Böylece buttonun tüm yatayı kaplaması ortadan kaldırılmış olunur. Ekranın altında en sağ yapışması için “layout_alignParentRight=true” atanır. “id=btnNext” değeri verilir.

ButtonNext

Sıra geldi ünvan text’inin oluşturulmasına. Ünvanın yazılacağı Medium Text aşağıda görüldüğü gibi “Prev” buttonun üstüne gelicek şekilde sürüklenir. Görüldüğü gibi tüm elemanlar, RelativeLayout özelliği ile bir başka nesneye göre referans alınıp create edilmektedir.

text

Aşağıdaki adımlar izlenerek ilgili “txtTitle” ekrana ortalanır ve id değerine “txtTitle” verilir.

Title

Son olarak imagelerin gözükeceği “ImageView” “txtTitle” text’inin üstüne sürüklenir.

TextMed

Aşağıdaki adımlar tek tek yapılır: Ekranın yukarısında gözükmesi için “alignParentTop=true” atanır. Ekranın ortalanması için “centerHorizontal=true” verilir. “txtTitle”‘a kadar uzamaması için “layout_above” temizlenir. Üstten boşluk için “10dp” verilir. Genişlik ve yükseklik için “160dp” verilir.

ImageView

Not: Mobil cihazlarda uzunluk olarak “dp” yani “Density-independent pixels” birimi kullanılır. “Pixel” ile olan oranları aşağıdaki tabloda verilmiştir.

oranlar

Daha sonra “Medium Text” yani “txtTitle”, “Image View”‘ın altına sürüklenir. Ve aşağıdaki maddeler sıra ile yapılır:”layout_above” temizlenerek aşağıya doğru uzayan text kısım düzeltilmiş olunur. Ayrıca üstten “10dp” boşluk bırakılır.

MediumText2

MediumText

Son olarak açıklama kısmı için “Small Text” “”Medium Text”‘in altına sürüklenir. Burada amaç aday hakkındaki bilgilerin yazılmasıdır. Ve aşağıdaki adımlar yapılır. ID olarak “textDescription” atanmıştır. Yana doğru genişleyerek warp yapıcak şekilde yazıların genişlemesi için “gravity=center_horizontal” atanmıştır. Ekranı ortalaması için “layout_centerHorizontal=true” atanmıştır.

txtDescription

Böylece ekran tasarımı tamamlanmış olunur. Son hali aşağıdaki gibidir.

screen

Kodlamaya başlanmadan önce aşağıdaki gibi “DataLibrary” adlı yardımcı bir kütüpahane oluşturulur. “Portable Class Library” IOS, Android ve Windows için uyumlu bir kütüpahane olacaktır.

ClassLibrary

Library.cs adlı bir sınıf aşağıdaki gibi oluşturulur: Amaç gösterilecek verinin data modelini oluşturmaktır. Aşağıda görüldüğü gibi “Title, Description ve Image” propertyleri sadece kendi namespace’i altında atanabilecek şekilde “internal” olarak yaratılmışlardır.

LibraryManager.cs: (Bölüm1) Bu sınıfta amaç InitData() methodu ile dummy dataların oluşturulması ve “Library[]” dizisinin mobilde gösterilecek bu datalar ile doldurulmasının sağlanmasıdır. Constructer’ında libraries array’ine ilgili Library[] datası atanır.

LibraryManager.cs: (Bölüm2)  Aşağıda görüldüğü gibi ilgili data içinde buttonlar tıklandığı zaman ileri ve geri şeklinde veriler arasında gezilmesi için gerekli methodlar yazılmıştır. “lastIndex” değişkenin’e dizideki toplam eleman sayısı atanmıştır. Sayfa yüklendiğinde ilk kayda gidilebilmesi için “MoveFirst()” methodu yazılmış ve “currentIndex=0″ atanmıştır. “currentIndex” o anda üzerinde bulunulan kaydın index’ini temsil etmektedir.

Aşağıda “Current” property’si o anda Library[] datası içinde bulunulan geçerli datayı vermektedir. “CanMovePrev” property’si dizi içinde geriye dönüşlerde son kayda gelinip gelinmediğine bakmaktadır. Aynı şekilde  “CanMoveNext” property’si dizi içinde ileri hareketlerde dizinin son kaydına gelinip gelinmediğine bakmaktadır.

Son olarak “Prev” buttonuna basılınca eğer ilk kayda gelinmemiş ise bir önceki kayda ait index’in “currentIndex“‘e atanması “MovePrev()” methodu ile sağlanır. Aynı şekilde “Next” buttonuna basılınca eğer son kayda gelinmemiş ise bir sonraki kayda ait index’in “currentIndex“‘e atanması “MoveNext()” methodu ile sağlanır.

Yukarıda dikkat ederseniz bir çeşit Iterator Design Pattern kullanılmıştır. “İlk ve Son” kayıt(“First()”, “Next()”), “Geçerli kayıt(“CurrentItem()”)”, “Son kayıt kontrolü(“IsDone()”)”, “Geçerli index’in alınması “ConcreteIterator”. Tüm bu yapıları içerisinde barındırmaktadır. Tasarım desenlerinin ne zaman ve nasıl karşımıza çıkacağı hiç belli olmadığı için, hepsi hakkında bir fikir sahibi olmak ve gerektiğinde nerede ve nasıl kullanılabileceğini tahmin etmek kod kalitesi anlamında hayati bir önem kazanmaktadır. İlerki bölümlerde ilgili “Prev” ve “Next” buttonlarına tıklanılması sonucunda bu kütüpahanenin datalar arasında gezinmede ne kadar faydalı olduğunu hep beraber göreceğiz.

Iterator

 iterator

LibraryManager.cs(Full):

Şimdi sıra geldi yukarıda data olarak atadığımız profil resimlerinin projeye eklenmesine. Resimlerin ekeleneceği alan “Resources/drawable” altındadır. Uzantıları “.png” olması gerekmektedir. Aşağıda görüldüğü gibi profiller için tanımlanmış image’ler drawable klasörü altına eklenmiştir.

Not: Resimlerin isimlerinde ““,”_” gibi karakterler olmamalıdır! Hata verir. Ve hatayı bulmanız saç baş yoldurabilir:)

draw

Ekran üzerinde yani “layout/Main.axaml”‘de yapılan UI’ın kodlarının yazılacağı yer “MainActivity.cs“‘dir.

Öncelikle UI üzerindeki neslere kod tarafında erişelim. Aşağıdaki gibi tanımlanan UI elemanları “Id” değerleri ile erişilir. Burada dikkat edilmesi gereken konu “Resource.Id” ile tüm nesnelerin id değerlerinin sayısal bir karşılığının olmasıdır.

Örnek Resource.Designer.cs: UI taraftaki elemanların “Id” değerlerinin sayısal karşılığı aşağıdaki gibidir.

Şimdi önceden oluşturduğumuz “LibraryManager.cs” sınıfını da devreye sokarak, buttonlara basılınca ileri ve geri işlemlerini yapalım: “OnCreated()” medhodunda aşağıda görüldüğü gibi “click” eventine ilgili methodlar bağlanmıştır. Ayrıca “MoveFirst()” ile elimizdeki ilk dataya yönlendirilmiş ve UpdateUI() ile de çekilen datalar ekrana basılmıştır.

UpdateUI():  Aşağıda görüldüğü gibi “Title ve Description”, o anki libManager altındaki datadan çekilmektedir. Önemli bir nokta “imgPerson.SetImageResource()”‘de “Resource/drawable” altındaki bir image’in  sayısal karşılığı beklenmektedir. Yani yine örnek amaçlı “imgPerson.SetImageResource(Resource.Drawable.Messi);” ilgili Image View’a resmin atanması içi yeterli olmaktadır. Bu durumda Resource.Designer.cs’deki resimlerin sayısal karşılığının bilinmesi ve eldeki data kümesinden gelen image ismine göre “int” value değerinin atanması gerekmektedir. Dikkat edilir ise “buttonNext ve buttonPrev”‘in enable özelliği yazılan Library sayesinde kolaylıkla “CanMove” ve “CanNext” sayesinde atana bilmektedir. Böylece başka bir projede hazırladığımız bir sınıfın(LibraryManager.cs) mobilde kullanıcı etkileşiminde ne denli yararlı olduğunu gördük.

Şimdi isterseniz ilgili resimlerin sayısal karşılığının atanması işlemini aşağıda görülen “ResourceHelper.cs” static helper sınıfı altında yapalım. Görüldüğü gibi “switch-case” yapısı altında gelen image ismine karşlık “Resource.Drawable” sınıfı altındaki sayısal karşılık dönülmektedir.

İleri ve geri buttonları tıklandığında “LibraryManager” sınıfından faydalanılarak bir önceki veya bir sonraki kayda gidilerek, “UpdateUI()” methodu ile ekrana basılır.

MainActivity.cs(Full):

ResourceHelper.cs-1:

Şimdi yukarıdaki koda bakıldığında her yeni eklenecek yada çıkarılacak resim için kodun değiştirilmesi ve “switch-case” yapısına yeni kodların eklenmesi yada çıkarılması gerekmektedir. Tabi bu doğru bir yaklaşım değildir. Bu image konusu “Android” programlamada kanayan bir konudur. Aynı işlem Xamarin IOS ortamında resimlerin “int” sayısal bir karşılığına ihtiyaç duyumladan kolaylıkla atanabilmektedir.

Örnek (IOS): “UIImage.FromBundle(“Messi”)” Burada resim için sayısal bir karşılık beklenmediği için Xamarin IOS ortamında imageler ile çalışmak Android ortamda çalışmaya göre çok daha kolaydır.

ResourceHelper.cs-2:

Bu durumda sistemi optimize etmek adına yukarıda görülen “System.Reflection” sınıfına ait yapı kullanılmıştır. Gelen image ismi, “FieldInfo” sınıfı sayesinde “Resource.Drawable” tipine bağlı olarak “int” değer karşılığı çekilmiş ve geri dönülmüştür. Böylece yeni bir image sisteme eklense dahi çalışma şekli “sayısal karşılıktan ==> string image ismine” döndürüldüğü için herhangi bir kod değişikliğine ihtiyaç duyulmamaktadır.

Not: Burada reflection ile çekilen image bir “Dictionary” listesine eklenmiştir. Daha sonra aynı image çekilmek istediğinde ilgili listeye bakılmış yok ise eklenmiş, var ise listedeki image geri dönülmüştür. Böylece sistemi yoran reflection yapısı her image için tekrar tekrar çağrılmamış ve bir çeşit “FlyWeight Design Pattern” bize anımsatmıştır. Yapısal(Structural) tasarım kalıplarından olan FlyWeight, bellek tüketimini optimize etmek amacıyla kullanılan bir desendir. Aslında bir depo mantığı içeren kalıp olduğu düşünülebilir. Aşağıda da dikkat ederseniz belli bir key’e göre Dictionary’den çekilen imageler “FlyweightFactory”, profile bakan “Client”, reflection ile çekilen image ait int value karşlığı “FlyWeight”, “+Operation”. Burada “ConcreteFlyweight” tabiki de yoktur. “instrinsicState” olarak yani ortak paylaşılan özellik resimlerin “value” değerleridir. Herhangi bir “Extrinsic State” de yoktur. Görüldüğü gibi bu yapı bir “FlyWeight” tasarım kalıbı ile birebir örtüşmemektedir. Ama bellek tüketimi azaltmak amaçlı her seferinde image value değeri reflection ile çekilmiyip var olan resimler için belli bir havuzdan verilmesi bana göre ilk akla “FlyWeight” tasarım prensibini getirmektedir.

Flyweight pattern

flyweight

Uygulamanın çalıştırılması durumunda android emulator’de karşımıza çıkan son hali aşağıdaki gibidir.

work

Android telefonlarda çalışacak”.apk” uzantılı setup paketinin oluşturulması için proje üzerine sağ tıklanıp “deploy” seçeneğin seçilmesi yeterlidir . Eğer deployment esnasında “please select valid device before running the application” hatası alınır ise ayrı bir proje olarak hazırlanan “DataLibrary(Portable)” sağ tıklanıp aşağıda görüldüğü gibi Targets bölümündeki “Change” tıklanır ve hedeflerden Xamarin.IOS ile başlıyan tüm hedefler kaldırılır. Böylece uygulama sadece Android için deploy edilmiş olunur.

Step1:

Error1

Step2:

Error2

Deploy yapılacak Android telefon işletim sistemi “JobProfile” sağ tıklanıp properties seçildiğinde, aşağıda görülen ekrandan deploy işlemi yapılacak android işletim sistemi seçilir.

version

Böylece Xamarin ile Android platformu için baştan sona bir profile uygulaması yazdık. Harici proje olarak yazılan bir kütüpahanenin, mobile bir uygulamada kullanıcı etkileşiminde ve görsel açıdan ne kadar faydalı olabileceğini, birkaç tasarım kalıbından esinlenerek de hem bellek yönetiminde hem de user interactivityde ne gibi kolaylıklar sağlıyacağını hep beraber gördük.

Geldik bir makalenin daha sonuna. Yeni bir makalede görüşmek üzere hoşçakalın.

Kaynaklar: https://developer.xamarin.com, Mobile Design Pattern Gallery. 2nd Edition O’Reilly, https://pluralsight.com

Source Code: https://github.com/borakasmer/XamarinJobProfile

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

4 Cevaplar

  1. Emre dedi ki:

    Hocam merhabalar android uygulama geliştirmek istiyorum c# bilgim var xamarin i yeni keşfettim fakat fazla türkçe kaynak bulamadım. Android studio yerine visual studioya alışık olduğumdan daha çok ilgimi çekti yemeksepeti tarzı bir uygulama geliştirilebilir mi xamarin ile mümkünse bende gerekli dökümanları indirip xamarin ile başlayacağım teşekkürler.

    • borsoft dedi ki:

      Selam Emre,

      Evet istediğin mobil uygulamayı Cross Platform, Xamarin ile geliştirebilirsin.

      İyi çalışmalar.

      • Emre dedi ki:

        Hocam yorumunuz için teşekkür ederim. Ben sağlam bir temel oluşturmaya çalışıyorum.Xamarin ile ilgili dökümanları indirdim ama benm yapmak istediğim sistem hem web hemde androidde çalışacak xamarin ile mobile başlamadan önce web e başlamak mı lazım. Mobilde veri tabanı işlemlerini pek bilmiyorum ve derslere bakıyorum şuanda ama bazı aklımda kalan şeylerde cevap bulursam daha iyi bir başlangıç yapacağıma inanıyorum

        • borsoft dedi ki:

          Selam Emre,

          Mobile ve Web farklı platformlar. C# ve algoritma önce öğrenecem diyorsan. O başka bir konu.

          İyi çalışmalar.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir