Xamarin ile Tasarım Desenleri Sayesinde Mobilde Profiller Arası Gezinme
Selamlar;
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.
Resources/layout/Main.axml: Aşağıda görüldüğü gibi UI kısmının tasarlandığı alan burasıdır.
Buradan “Source” tabına geçildiğin de aşağıdaki gibi bir koda erişilir:
1 2 3 4 5 6 7 8 9 10 11 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/MyButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/Hello" /> </LinearLayout> |
Ö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.
1 2 3 4 5 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> </RelativeLayout> |
Ö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 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.
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.
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.
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.
Aşağıdaki adımlar izlenerek ilgili “txtTitle” ekrana ortalanır ve id değerine “txtTitle” verilir.
Son olarak imagelerin gözükeceği “ImageView” “txtTitle” text’inin üstüne sürüklenir.
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.
Not: Mobil cihazlarda uzunluk olarak “dp” yani “Density-independent pixels” birimi kullanılır. “Pixel” ile olan oranları aşağıdaki tabloda verilmiştir.
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.
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.
Böylece ekran tasarımı tamamlanmış olunur. Son hali aşağıdaki gibidir.
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.
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.
1 2 3 4 5 6 |
public class Library { public string Title { get; internal set; } public string Description { get; internal set; } public string Image { get; internal set; } } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataLibrary { public class LibraryManager { private readonly Library[] libraries; public LibraryManager() { libraries = InitData(); } private Library[] InitData() { var initData = new Library[] { new Library() { Title="Android for .Net Developers", Description="Provides an overview of the tools uses in Android"+ "development process including the newly relased Android Studio.", Image="adam" }, new Library() { Title="Android Dreams, Widget, Notifications", Description="Provide users with a rich and interactive experiance "+ "without ever requiring them to open your app.", Image="Hubbard" }, new Library() { Title="Android Phptp/Video Programming", Description="Learn How to capitalize on the Android camera "+ "within your apps to capture still photos and video.", Image="Messi" }, new Library() { Title="Android Location-Based Apps", Description="Cove the wide range of Android location capabilities "+ "including determining user location, power managment, and"+ "translating location to human-readble addresses", Image="Nathan" } }; return initData; } } } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class LibraryManager { private int lastIndex; int currentIndex = 0; public LibraryManager() { lastIndex = libraries.Length - 1; } public void MoveFirst() { currentIndex = 0; } } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public Library Current { get { return libraries[currentIndex]; } } public bool CanMovePrev { get { return currentIndex > 0; } } public bool CanMoveNext { get { return currentIndex < lastIndex; } } |
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.
1 2 |
public void MovePrev() { if (currentIndex > 0) { --currentIndex; } } public void MoveNext() { if (currentIndex < libraries.Length - 1) { ++currentIndex; } } |
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
LibraryManager.cs(Full):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataLibrary { public class LibraryManager { private readonly Library[] libraries; private int lastIndex; int currentIndex = 0; public LibraryManager() { libraries = InitData(); lastIndex = libraries.Length - 1; } private Library[] InitData() { var initData = new Library[] { new Library() { Title="Android for .Net Developers", Description="Provides an overview of the tools uses in Android"+ "development process including the newly relased Android Studio.", Image="adam" }, new Library() { Title="Android Dreams, Widget, Notifications", Description="Provide users with a rich and interactive experiance "+ "without ever requiring them to open your app.", Image="Hubbar" }, new Library() { Title="Android Phptp/Video Programming", Description="Learn How to capitalize on the Android camera "+ "within your apps to capture still photos and video.", Image="name" }, new Library() { Title="Android Location-Based Apps", Description="Cove the wide range of Android location capabilities "+ "including determining user location, power managment, and"+ "translating location to human-readble addresses", Image="Nathan" } }; return initData; } public void MoveFirst() { currentIndex = 0; } public void MovePrev() { if (currentIndex > 0) { --currentIndex; } } public void MoveNext() { if (currentIndex < libraries.Length - 1) { ++currentIndex; } } public Library Current { get { return libraries[currentIndex]; } } public bool CanMovePrev { get { return currentIndex > 0; } } public bool CanMoveNext { get { return currentIndex < lastIndex; } } } } |
Ş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:)
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class MainActivity : Activity { Button buttonNext; Button buttonPrev; TextView txtTitle; TextView txtDescription; ImageView imgPerson; protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); buttonNext = FindViewById<Button>(Resource.Id.btnNext); buttonPrev = FindViewById<Button>(Resource.Id.btnPrev); txtTitle = FindViewById<TextView>(Resource.Id.txtTitle); txtDescription = FindViewById<TextView>(Resource.Id.textDescription); imgPerson = FindViewById<ImageView>(Resource.Id.imgProfile); } } |
Örnek Resource.Designer.cs: UI taraftaki elemanların “Id” değerlerinin sayısal karşılığı aşağıdaki gibidir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public partial class Id { // aapt resource value: 0x7f050001 public const int btnNext = 2131034113; // aapt resource value: 0x7f050000 public const int btnPrev = 2131034112; // aapt resource value: 0x7f050002 public const int imgProfile = 2131034114; // aapt resource value: 0x7f050004 public const int textDescription = 2131034116; // aapt resource value: 0x7f050003 public const int txtTitle = 2131034115; static Id() { global::Android.Runtime.ResourceIdManager.UpdateIdValues(); } private Id() { } } |
Ş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.
1 2 3 4 5 |
buttonPrev.Click += ButtonPrev_Click; buttonNext.Click += ButtonNext_Click; libManager = new LibraryManager(); libManager.MoveFirst(); UpdateUI(); |
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.
1 2 3 4 5 6 7 8 |
private void UpdateUI() { txtTitle.Text = libManager.Current.Title; txtDescription.Text = libManager.Current.Description; imgPerson.SetImageResource(ResourceHelper.TranslateDrawable(libManager.Current.Image)); buttonNext.Enabled = libManager.CanMoveNext; buttonPrev.Enabled = libManager.CanMovePrev; } |
Ş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.
1 2 3 4 5 6 7 8 9 10 11 |
private void ButtonNext_Click(object sender, EventArgs e) { libManager.MoveNext(); UpdateUI(); } private void ButtonPrev_Click(object sender, EventArgs e) { libManager.MovePrev(); UpdateUI(); } |
MainActivity.cs(Full):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
using System; using Android.App; using Android.Content; using Android.Runtime; using Android.Views; using Android.Widget; using Android.OS; using DataLibrary; namespace JobProfile { [Activity(Label = "JobProfile", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity { Button buttonNext; Button buttonPrev; TextView txtTitle; TextView txtDescription; ImageView imgPerson; LibraryManager libManager; protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); buttonNext = FindViewById<Button>(Resource.Id.btnNext); buttonPrev = FindViewById<Button>(Resource.Id.btnPrev); txtTitle = FindViewById<TextView>(Resource.Id.txtTitle); txtDescription = FindViewById<TextView>(Resource.Id.textDescription); imgPerson = FindViewById<ImageView>(Resource.Id.imgProfile); buttonPrev.Click += ButtonPrev_Click; buttonNext.Click += ButtonNext_Click; libManager = new LibraryManager(); libManager.MoveFirst(); UpdateUI(); // Get our button from the layout resource, // and attach an event to it } private void ButtonNext_Click(object sender, EventArgs e) { libManager.MoveNext(); UpdateUI(); } private void ButtonPrev_Click(object sender, EventArgs e) { libManager.MovePrev(); UpdateUI(); } private void UpdateUI() { txtTitle.Text = libManager.Current.Title; txtDescription.Text = libManager.Current.Description; imgPerson.SetImageResource(ResourceHelper.TranslateDrawableWithReflection(libManager.Current.Image)); buttonNext.Enabled = libManager.CanMoveNext; buttonPrev.Enabled = libManager.CanMovePrev; } } } |
ResourceHelper.cs-1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using System.Reflection; namespace JobProfile { public static class ResourceHelper { public static int TranslateDrawable(string name) { int resourceValue = -1; switch (name) { case "adam": { resourceValue = Resource.Drawable.adam; break; } case "Hubbar": { resourceValue = Resource.Drawable.Hubbard; break; } case "name": { resourceValue = Resource.Drawable.Messi; break; } case "Nathan": { resourceValue = Resource.Drawable.Nathan; break; } } return resourceValue; } } } |
Ş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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
static Dictionary<string, int> resourceDictionary = new Dictionary<string, int>(); public static int TranslateDrawableWithReflection(string name) { int resourceValue = -1; if (resourceDictionary.ContainsKey(name)) { resourceValue = resourceDictionary[name]; } else { Type drawableType = typeof(Resource.Drawable); FieldInfo resourceFileInfo = drawableType.GetField(name); resourceValue = (int)resourceFileInfo.GetValue(null); resourceDictionary.Add(name, resourceValue); } return resourceValue; } |
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
Uygulamanın çalıştırılması durumunda android emulator’de karşımıza çıkan son hali aşağıdaki gibidir.
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:
Step2:
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.
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
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.
Selam Emre,
Evet istediğin mobil uygulamayı Cross Platform, Xamarin ile geliştirebilirsin.
İyi çalışmalar.
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
Selam Emre,
Mobile ve Web farklı platformlar. C# ve algoritma önce öğrenecem diyorsan. O başka bir konu.
İyi çalışmalar.