Yeniden merhabalar,
Unity‘de bir dizi veriyi UI‘da göstermek için Scroll View kullanmak idealdir (örneğin oyun içi market veya leaderboard). Ancak göstereceğiniz verinin boyutu arttıkça (örneğin leaderboard’da binlerce satır [entry] göstermek isteyebilirsiniz), Scroll View’ın performansı düşecektir çünkü her bir entry için ayrı bir UI GameObject’i oluşturacaksınız. Bu performans sorununu çözmenin yolu, her bir entry için ayrı bir GameObject oluşturmak yerine, sadece ekranda görünen entry’ler için elimizde bir düzine UI GameObject’i tutup onları tekrar tekrar kullanmaktır. Bunun için, diyelim Scroll View’ı aşağı kaydırdıkça, ekranın üst kenarından dışarı çıkan GameObject’leri ekranın alt kenarına ışınlayıp tekrardan kullanabiliriz. Böylece sadece birkaç GameObject ile binlerce entry’i Scroll View’da gösterebiliriz:

Hazırsanız derse başlayalım!
Bu iş için hatırı sayılır miktarda kod yazmak gerekiyor. O yüzden süreci hızlandırmak adına hazır bir plugin kullanacağız. Asset Store’da bu konuda ücretli plugin’ler (1, 2) bulunmakta ama biz GitHub üzerindeki MIT lisanslı ücretsiz plugin’lere bakacağız. Araştırma yaparken şu 3 ücretsiz plugin ile karşılaştım:
- https://github.com/sinbad/UnityRecyclingListView
- (+) kod olarak en temiz bulduğum plugin bu
- (-) sadece dikey (Vertical) Scroll View’larda çalışıyor
- (-) Scroll View’daki tüm GameObject’lerin yükseklikleri aynı olmak zorunda (bir obje 50 piksel yüksekliğinde, öbürü 100 piksel yüksekliğinde olamaz)
- üstteki şartlar sağlandığında bu plugin’i kullanmayı tavsiye ediyorum
- https://github.com/MdIqubal/Recyclable-Scroll-Rect
- (+) yatay (Horizontal) ve grid tabanlı Scroll View’larda da çalışıyor
- (-) scrollbar desteklemiyor
- (-) ekranda gözükmekte olan entry’leri refresh etmeyi desteklemiyor (örneğin elimizdeki veri değişirse bu gerekli)
- (-) tüm entry’leri temizleme (clear) desteği yok
- (-) ekran çözünürlüğü veya Scroll View’in genişliği değişirse, ekrandaki GameObject’lerin genişliği otomatik olarak değişmiyor. Örneğin telefonu portrait moddan landscape moda geçirirseniz, ekrandaki GameObject’lerin genişliği ufacık kalıyor
- tüm bu olumsuz noktalardan dolayı, bu plugin’in kullanımından bahsetmeyeceğim
- https://github.com/qiankanglai/LoopScrollRect
- (+) yatay (Horizontal) ve grid tabanlı Scroll View’larda da çalışıyor
- (+) farklı yüksekliklere sahip GameObject’leri destekliyor
- (-) kod olarak çok hoş değil. Örneğin kodda SendMessage fonksiyonunu kullanıyor ve UI GameObject’inin prefab’ını Resources klasörüne koymanızı gerektiriyor (ama kodu biraz değiştirerek bu sorunları çözeceğiz)
- (-) kurulumu biraz uğraştırıyor. Örneğin scrollbar’ı otomatik oluşturmuyor, elle oluşturmanız gerekiyor
- eğer yatay/grid tabanlı Scroll View kullanıyorsanız veya her bir entry’nin Scroll View’daki yüksekliği farklı olacaksa, bu 3 alternatif içinden mecburen bunu kullanmak zorundasınız
Bu derste 1. ve 3. plugin’lerin kullanımını göreceğiz. Takıldığınız bir yer olursa, dersteki her şeyin bitmiş halini şu linkten indirebilirsiniz: https://www.dropbox.com/s/775levbi6fncl4i/ListViewDemo.unitypackage?dl=0
Derste basit bir oyun içi market yapacağız. Marketteki eşyaların her birinin kendine has bir ismi ve ücreti olacak. Bir eşyaya tıklayarak onu seçebileceğiz. Seçili eşyanın arkaplan rengi kırmızı olacak:

Öncelikle ilk plugin’in kullanımını görelim.
UnityRecyclingListView
Şu linkten plugin’i indirin: https://github.com/sinbad/UnityRecyclingListView/archive/master.zip. İndirdiğiniz zip‘in içindeki UnityRecyclingListView-master\Source
klasörünü, Unity projenizin olduğu konumdaki Assets klasörüne çıkarın. Son olarak, zip’teki LICENSE dosyasını da çıkardığınız klasörün içine atın:

Eski bir Unity sürümü kullanıyorsanız, Invalid accessor body =>', expecting;' or `{'
gibi birkaç hata alabilirsiniz. Bu hataları çözmek için:
get => scrollRect.verticalNormalizedPosition;
satırınıget { return scrollRect.verticalNormalizedPosition; }
olarak değiştirinset => scrollRect.verticalNormalizedPosition = value;
satırınıset { scrollRect.verticalNormalizedPosition = value; }
olarak değiştirin- diğer sıkıntılı satırları da benzer şekilde değiştirin
Gelelim plugin’in kullanımına:
- sahnenizde GameObject-UI-Scroll View ile yeni bir Scroll View objesi oluşturun
- Scroll View objesinin Horizontal seçeneğini kapatın, Scrollbar Horizontal objesini silin
- Scroll View’a Recycling List View component’i ekleyin
- Scroll View/Viewport/Content‘e sağ tıklayıp yeni bir UI-Image objesi oluşturun. Oluşan objenin ismini TestItem olarak değiştirin. Oyun içi marketteki entry’leri, TestItem’ın klonları ile UI’da göstereceğiz. TestItem’ın RectTransform’unu şu şekilde değiştirin:

- TestItem’a tıklayabileceğimiz için, ona Button component’i ekleyin
- şimdi elimizdeki veriye göre TestItem’ı kişiselleştirmemiz lazım. Hatırlarsanız elimizdeki veri, marketteki eşyaların isim ve ücretlerinden ibaret. Bunun için TestItem’ın içerisinde şu şekilde 2 Text objesi oluşturun:

- TestItem adında yeni bir C# script oluşturup içeriğini şu şekilde değiştirin:
using UnityEngine; using UnityEngine.UI; public class TestItem : RecyclingListViewItem { public Text isimText; public Text ucretText; public Button buton; public Image arkaplan; [HideInInspector] public bool itemYeniOlusturuldu = true; }
- TestItem’ın hangi component’lerini kod ile güncelleyeceksek, o component’ler için birer değişken oluşturduk. Burada dikkat etmemiz gereken en önemli şey, oluşturduğumuz class’ın RecyclingListViewItem sınıfından türemesi. “itemYeniOlusturuldu” değişkeninin ne işe yaradığını bir sonraki script’te göreceksiniz
- sahnedeki TestItem objesine, Test Item component’ini verip değişkenlerin değerlerini doldurun:

- TestItem objesini Project paneline sürükle-bırak yaparak bir prefab‘a çevirin ve ardından sahneden silin. Oluşturduğunuz prefab’ı Recycling List View component’indeki Child Prefab değişkenine değer olarak verin. Aynı component’teki Row Padding değeri, oyun esnasında 2 TestItem objesi arasında kaç piksel boşluk olacağını belirler. Ben onu 0 yaptım. Pre Alloc Height değişkenini 0 olarak bırakabilirsiniz
- RecyclingListViewTest adında yeni bir C# script oluşturun:
using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class RecyclingListViewTest : MonoBehaviour { // Oyun içi marketteki eşyaların bilgilerini tutan veri türü public class ItemBilgileri { public string isim; public int ucret; public ItemBilgileri( string isim, int ucret ) { this.isim = isim; this.ucret = ucret; } } public RecyclingListView scrollView; private ScrollRect scrollRect; // Markette en başta kaç eşya olacağı public int ilkItemSayisi = 50; // Her Q tuşuna basınca markete kaç yeni eşya geleceği public int eklenenItemSayisi = 5; // Marketteki tüm eşyaların verisi private List<ItemBilgileri> itemBilgileri; // Hangi index'teki eşyanın seçili olduğu private int seciliItemIndex = -1; private void Start() { scrollRect = scrollView.GetComponent<ScrollRect>(); // Marketteki eşyaların verisini çek (bu örnekte veriyi rastgele oluşturuyoruz) itemBilgileri = new List<ItemBilgileri>( ilkItemSayisi ); for( int i = 0; i < ilkItemSayisi; i++ ) itemBilgileri.Add( RastgeleItemOlustur() ); // Scroll View'ı aşağı-yukarı kaydırdıkça, kameranın görüş alanına giren // her yeni entry için ItemiGuncelle fonksiyonunu çağır scrollView.ItemCallback = ItemiGuncelle; // Markette kaç eşya olduğu bilgisini RecyclingListView'e bildir scrollView.RowCount = itemBilgileri.Count; // Oyunun başında bazen "Scrollbar Vertical" objesi TestItem'ların içine giriyor, // bu satır o sorunu düzeltmeye yarıyor scrollRect.horizontalScrollbarSpacing = scrollRect.horizontalScrollbarSpacing; } private void Update() { // Her Q tuşuna basınca, eklenenItemSayisi kadar yeni eşyayı markete ekle if( Input.GetKeyDown( KeyCode.Q ) ) { for( int i = 0; i < eklenenItemSayisi; i++ ) itemBilgileri.Add( RastgeleItemOlustur() ); // RecyclingListView her güncellenişinde, işi garantiye almak için scrollbar'ı // en tepeye ışınlıyor. Marketten eşya silersek bu işlemi yapması önemli çünkü // aksi taktirde scrollbar'ın olduğu konumdaki eşyalar silinmiş olabilir ve // scrollbar artık boşluğa bakıyor olur. Ama biz markete yeni eşya eklediğimiz // için, scrollbar'ın olduğu konumdaki eşyaların silinmesi imkansız. Bu durumda // boş yere scrollbar'ın en tepeye ışınlanması bizi rahatsız etmekten başka bir // işe yaramamakta. Onun için scrollbar'ın en son konumunu ve scroll hızını // birer değişkende tut ve RecyclingListView'ı güncelledikten sonra bu değerleri // scrollbar'a geri ata Vector2 position = scrollRect.content.anchoredPosition; Vector2 scrollSpeed = scrollRect.velocity; // Markette artık kaç eşya olduğu bilgisini RecyclingListView'e bildir scrollView.RowCount = itemBilgileri.Count; // Scrollbar'ın en son konumunu ve hızını geri ata scrollRect.content.anchoredPosition = position; scrollRect.velocity = scrollSpeed; } // W tuşuna basınca, markette seçili bir eşya varsa Scroll View'ı otomatik olarak o eşyaya odakla if( Input.GetKeyDown( KeyCode.W ) && seciliItemIndex >= 0 && seciliItemIndex < itemBilgileri.Count ) scrollView.ScrollToRow( seciliItemIndex ); // E tuşuna basınca marketteki tüm eşyaları sil if( Input.GetKeyDown( KeyCode.E ) ) { itemBilgileri.Clear(); scrollView.RowCount = 0; } } // Market için rastgele eşya verisi oluşturmaya yarar private ItemBilgileri RastgeleItemOlustur() { return new ItemBilgileri( "Item " + itemBilgileri.Count, Random.Range( 1, 1000 ) ); } // index'teki eşyanın TestItem'ı kameranın görüş alanına girdi; TestItem'ın içeriğini // o index'teki eşyanın verisini gösterecek şekilde güncelle private void ItemiGuncelle( RecyclingListViewItem i, int index ) { TestItem item = (TestItem) i; // Isim ve Ucret Text'lerini güncelle item.isimText.text = itemBilgileri[index].isim; item.ucretText.text = itemBilgileri[index].ucret + " TL"; // Eğer seçili eşya bu eşya ise, TestItem'ın arkaplan rengini kırmızı yap (if), // değilse beyaz yap (else) if( index == seciliItemIndex ) item.arkaplan.color = new Color32( 230, 57, 70, 255 ); else item.arkaplan.color = new Color32( 241, 250, 238, 255 ); // Eğer bu TestItem için ItemiGuncelle fonksiyonu daha önce çağrılmadıysa if( item.itemYeniOlusturuldu ) { // Bu kodu sadece 1 kez çalıştır (aşağıdaki kodu birden çok kez çağırmak boş yere performansı etkiler) item.itemYeniOlusturuldu = false; // TestItem'a her tıklandığında (onClick) ItemeTiklandi fonksiyonunu çağır // Delegate'ler hakkında daha fazla bilgi için: https://yasirkula.com/2019/10/29/unity-c-delegate-ve-eventler/ item.buton.onClick.AddListener( () => ItemeTiklandi( item ) ); } } // Bir TestItem'a tıklandı private void ItemeTiklandi( TestItem item ) { // Mevcut seçili eşyanın index'ini bir değişkende tut int oncekiSeciliItemIndex = seciliItemIndex; // Seçili eşya index'ini güncelle. TestItem'a atanan verinin index'ini // bulmak için CurrentRow değişkenini kullanmak yeterli seciliItemIndex = item.CurrentRow; // seciliItemIndex'indeki eşyanın TestItem'ı için ItemiGuncelle fonksiyonunu // tekrar çağır (böylece TestItem'ın arkaplanı kırmızı olacak). İlk parametre // hangi index'teki TestItem'ın güncelleneceğini, ikinci parametre ise o index'ten // itibaren kaç TestItem'ın güncelleneceğini belirler. Biz sadece // seciliItemIndex'teki tek bir TestItem'ın güncellenmesini istiyoruz scrollView.Refresh( seciliItemIndex, 1 ); // Eğer daha önceden bir eşya seçili idiyse, o eşyanın TestItem'ını da güncelle // (böylece o TestItem'ın arkaplanı kırmızı renkten geri beyaz renge dönecek) if( oncekiSeciliItemIndex >= 0 ) scrollView.Refresh( oncekiSeciliItemIndex, 1 ); } }
- kodda açıklanması gereken her yeri comment’lerle açıklamaya çalıştım. Özetle, oyunun başında RecyclingListView objesinin ItemCallback‘ine kendi fonksiyonumuzu kaydediyoruz ve akabinde RecyclingListView’a elimizdeki verinin kaç entry’den oluştuğunu RowCount ile söylüyoruz. Scroll View scroll oldukça, ItemCallback fonksiyonu yeni entry’ler için otomatik olarak çağrılıyor. Elimizdeki entry’lerin sayısı her değiştiğinde, bu değişikliği RowCount ile tekrardan RecyclingListView’a bildiriyoruz
- Recycling List View Test component’ini sahnenizdeki istediğiniz bir objeye verin. Component’teki Scroll View değişkenine değer olarak, sahnedeki Scroll View objesini verin
- oyunu çalıştırın. Test amaçlı Q tuşu ile markete yeni eşyalar ekleyebilir, W tuşu ile seçili eşyaya odaklanabilir, E tuşu ile de marketteki tüm eşyaları silebilirsiniz
LoopScrollRect
Şu linkten plugin’i indirin: https://github.com/qiankanglai/LoopScrollRect/archive/master.zip. İndirdiğiniz zip‘in içindeki LoopScrollRect-master\Assets\Scripts
klasörünü, Unity projenizin olduğu konumdaki Assets klasörüne çıkarın. Çıkardığınız klasördeki EasyObjectPool alt klasörünü silin. Son olarak, zip’teki LICENSE dosyasını da çıkardığınız klasörün içine atın:

Bu plugin’in kodunun o kadar güzel olmadığından bahsetmiştim. Kodu düzeltmenin ilk aşaması olarak EasyObjectPool alt klasörünü sildik. Bu yüzden kod şu anda hata verecek. Adım adım plugin’in kodunu düzeltelim/iyileştirelim (yapacağımız kod değişikliklerini açıklamayacağım çünkü plugin’in kaynak kodunu bilmenize gerek yok):
- LoopScrollPrefabSource script’ini şu şekilde güncelleyin:
using UnityEngine; using System.Collections.Generic; namespace UnityEngine.UI { public class LoopScrollRectItem : MonoBehaviour { [System.NonSerialized] public int CurrentRow; } [System.Serializable] public class LoopScrollPrefabSource { public Transform prefab; public int havuzIlkBoyutu = 5; private Stack<Transform> havuz; public Transform GetObject() { if( havuz == null ) { havuz = new Stack<Transform>( havuzIlkBoyutu ); for( int i = 0; i < havuzIlkBoyutu; i++ ) { Transform instance = Object.Instantiate( prefab, null, false ); instance.gameObject.SetActive( false ); havuz.Push( instance ); } } if( havuz.Count == 0 ) return Object.Instantiate( prefab, null, false ); else { Transform instance = havuz.Pop(); instance.gameObject.SetActive( true ); return instance; } } public void ReturnObject( Transform go ) { go.gameObject.SetActive( false ); go.SetParent( null, false ); havuz.Push( go ); } } }
- LoopScrollDataSource script’ini şu şekilde güncelleyin:
using UnityEngine; namespace UnityEngine.UI { public abstract class LoopScrollDataSource { public abstract void ProvideData( Transform transform, int index ); } public class LoopScrollSendIndexSource : LoopScrollDataSource { private readonly LoopScrollRect scrollView; public LoopScrollSendIndexSource( LoopScrollRect scrollView ) { this.scrollView = scrollView; } public override void ProvideData( Transform transform, int index ) { LoopScrollRectItem item = transform.GetComponent<LoopScrollRectItem>(); item.CurrentRow = index; if( scrollView.ItemCallback != null ) scrollView.ItemCallback( item, index ); } } public class LoopScrollArraySource<T> : LoopScrollDataSource { private readonly T[] objectsToFill; public LoopScrollArraySource( T[] objectsToFill ) { this.objectsToFill = objectsToFill; } public override void ProvideData( Transform transform, int idx ) { transform.SendMessage( "ScrollCellContent", objectsToFill[idx] ); } } }
- LoopScrollRect script’inde şu değişiklikleri yapın:
public LoopScrollDataSource dataSource = LoopScrollSendIndexSource.Instance;
satırınıpublic LoopScrollDataSource dataSource;
olarak değiştirin- biraz altındaki
dataSource = LoopScrollSendIndexSource.Instance;
satırınıdataSource = new LoopScrollSendIndexSource( this );
olarak değiştirin private bool m_ContentConstraintCountInit = false;
satırını[HideInInspector] public bool m_ContentConstraintCountInit = false;
olarak değiştirin- boş bir satıra
public System.Action ItemCallback;
değişkenini ekleyin protected LoopScrollRect()
constructor’ının içine şu satırı ekleyin:objectsToFill = null;
Artık koddaki tüm hatalar gitmiş olmalı. Gelelim plugin’in kullanımına:
- sahnenizde GameObject-UI-Loop Vertical Scroll Rect ile yeni bir Loop Vertical Scroll Rect objesi oluşturun (yatay [Horizontal] scroll istiyorsanız, Loop Horizontal Scroll Rect oluşturun). Kolaylık açısından, oluşan objenin ismini Scroll View olarak değiştirin
- eğer scrollbar istiyorsanız, Scroll View objesinin içerisinde UI-Scrollbar oluşturun. Loop Vertical Scroll Rect kullanıyorsanız, scrollbar’ın Direction değişkenini Top To Bottom yapın. Ardından scrollbar’ı ekranın kenarına hizalayın. Son olarak da, Scroll View’ın ilgili Scrollbar değişkenine, oluşturduğunuz Scrollbar objesini değer olarak verin
- Scroll View/Content‘teki Layout Group component’ini şu şekilde güncelleyin:
- Loop Vertical Scroll Rect için:

- Loop Horizontal Scroll Rect için:

- GridLayout kullanacaksanız, mevcut Layout Group component’ini silip yerine Grid Layout Group component’i ekleyin (buradaki Cell Size, TestItem’ların kaç piksel ebatında olacağını belirler):

- eğer Grid Layout Group’u Loop Horizontal Scroll Rect ile kullanacaksanız, Start Axis değişkenini Vertical, Child Alignment değişkenini Middle Left, Constraint değişkenini de Fixed Row Count olarak değiştirin
- Grid Layout Group kullanacaksanız, son olarak da GridDinamikEbat adında yeni bir C# script oluşturup onu Scroll View/Content objesine component olarak verin (bu script, ekranın çözünürlüğü değişince Grid Layout Group’un satır/sütun sayısını [Constraint Count] otomatik olarak en uygun değere ayarlar):
using UnityEngine; using UnityEngine.UI; [RequireComponent( typeof( GridLayoutGroup ) )] public class GridDinamikEbat : MonoBehaviour { private GridLayoutGroup gridLayout; private LoopScrollRect scrollView; private void OnRectTransformDimensionsChange() { if( gridLayout == null ) gridLayout = GetComponent<GridLayoutGroup>(); if( scrollView == null ) scrollView = GetComponentInParent<LoopScrollRect>(); Vector2 contentBoyutu = ( (RectTransform) transform ).rect.size; int yeniHucreSayisi; if( gridLayout.constraint == GridLayoutGroup.Constraint.FixedColumnCount ) yeniHucreSayisi = (int) ( ( contentBoyutu.x - gridLayout.padding.horizontal ) / ( gridLayout.cellSize.x + gridLayout.spacing.x ) ); else yeniHucreSayisi = (int) ( ( contentBoyutu.y - gridLayout.padding.vertical ) / ( gridLayout.cellSize.y + gridLayout.spacing.y ) ); if( yeniHucreSayisi < 1 ) yeniHucreSayisi = 1; if( gridLayout.constraintCount != yeniHucreSayisi ) { gridLayout.constraintCount = yeniHucreSayisi; scrollView.m_ContentConstraintCountInit = false; scrollView.RefillCells(); } } }
- Scroll View/Content‘in RectTransform’unu şu şekilde değiştirin:
- Loop Vertical Scroll Rect için (sağdaki scrollbar’ım 20 piksel genişliğinde olduğu için, sağdan [Right] 20 piksel boşluk bıraktım):

- Loop Horizontal Scroll Rect için:

- Scroll View/Content‘e sağ tıklayıp yeni bir UI-Image objesi oluşturun. Oluşan objenin ismini TestItem olarak değiştirin. Oyun içi marketteki entry’leri, TestItem’ın klonları ile UI’da göstereceğiz. TestItem’a tıklayabileceğimiz için, ona öncelikle bir Button component’i ekleyin
- az önce gördüğümüz Layout Group component’inden fark edeceğiniz üzere, bu plugin UI’ın layout sisteminden faydalanıyor. Bunun için, TestItem’da Layout Element veya Content Size Fitter olmak zorunda. TestItem’a Layout Element component’i ekleyin (Preferred Height, TestItem’ın kaç piksel yüksekliğinde olacağını belirler. Eğer Loop Horizontal Scroll Rect kullanıyorsanız, Preferred Height yerine Preferred Width‘e değer verin, bu durumda TestItem’ın kaç piksel genişliğinde olacağını belirlersiniz):

- şimdi elimizdeki veriye göre TestItem’ı kişiselleştirmemiz lazım. Hatırlarsanız elimizdeki veri, marketteki eşyaların isim ve ücretlerinden ibaret. Bunun için TestItem’ın içerisinde şu şekilde 2 Text objesi oluşturun (Loop Horizontal Scroll Rect için üste ismi, alta ücreti koyabilirsiniz):

- TestItem2 adında yeni bir C# script oluşturup içeriğini şu şekilde değiştirin:
using UnityEngine; using UnityEngine.UI; public class TestItem2 : LoopScrollRectItem { public Text isimText; public Text ucretText; public Button buton; public Image arkaplan; public LayoutElement layoutElement; [HideInInspector] public bool itemYeniOlusturuldu = true; }
- TestItem’ın hangi component’lerini kod ile güncelleyeceksek, o component’ler için birer değişken oluşturduk. Burada dikkat etmemiz gereken en önemli şey, oluşturduğumuz class’ın LoopScrollRectItem sınıfından türemesi. “itemYeniOlusturuldu” değişkeninin ne işe yaradığını bir sonraki script’te göreceksiniz
- sahnedeki TestItem objesine Test Item 2 component’ini verip değişkenlerin değerlerini doldurun:

- TestItem objesini Project paneline sürükle-bırak yaparak bir prefab‘a çevirin ve ardından sahneden silin. Oluşturduğunuz prefab’ı Scroll View objesindeki Prefab Source-Prefab değişkenine değer olarak verin (Havuz Ilk Boyutu‘nu olduğu gibi bırakabilirsiniz)
- LoopScrollRectTest adında yeni bir C# script oluşturun:
using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; public class LoopScrollRectTest : MonoBehaviour { // Oyun içi marketteki eşyaların bilgilerini tutan veri türü public class ItemBilgileri { public string isim; public int ucret; public ItemBilgileri( string isim, int ucret ) { this.isim = isim; this.ucret = ucret; } } public LoopScrollRect scrollView; // Markette en başta kaç eşya olacağı public int ilkItemSayisi = 50; // Her Q tuşuna basınca markete kaç yeni eşya geleceği public int eklenenItemSayisi = 5; // Marketteki her eşyanın yüksekliğinin farklı olup olmayacağı (test amaçlı) public bool rastgeleItemYuksekligi = false; // Marketteki tüm eşyaların verisi private List<ItemBilgileri> itemBilgileri; // Hangi index'teki eşyanın seçili olduğu private int seciliItemIndex = -1; private void Start() { // Marketteki eşyaların verisini çek (bu örnekte veriyi rastgele oluşturuyoruz) itemBilgileri = new List<ItemBilgileri>( ilkItemSayisi ); for( int i = 0; i < ilkItemSayisi; i++ ) itemBilgileri.Add( RastgeleItemOlustur() ); // Scroll View'ı aşağı-yukarı kaydırdıkça, kameranın görüş alanına giren // her yeni entry için ItemiGuncelle fonksiyonunu çağır scrollView.ItemCallback = ItemiGuncelle; // Markette kaç eşya olduğu bilgisini LoopScrollRect'e bildir scrollView.totalCount = itemBilgileri.Count; // LoopScrollRect'e ekrandaki tüm TestItem'ları yeniden oluşturmasını söyle scrollView.RefillCells(); } private void Update() { // Her Q tuşuna basınca, eklenenItemSayisi kadar yeni eşyayı markete ekle if( Input.GetKeyDown( KeyCode.Q ) ) { for( int i = 0; i < eklenenItemSayisi; i++ ) itemBilgileri.Add( RastgeleItemOlustur() ); // Markette artık kaç eşya olduğu bilgisini RecyclingListView'e bildir scrollView.totalCount = itemBilgileri.Count; // Eğer bu esnada Scroll View scroll olmuyor idiyse, scrollbar'ın yüksekliği/genişliği // otomatik olarak değişmiyor, Scroll View scroll olunca değişiyor. Scrollbar'ın // güncellenmesini garantilemek için, Scroll View'ı kod ile çok cüzi miktarda scroll et scrollView.OnScroll( new PointerEventData( EventSystem.current ) { scrollDelta = new Vector2( 0f, 0.001f ) } ); } // W tuşuna basınca, markette seçili bir eşya varsa Scroll View'ı otomatik olarak o eşyaya odakla if( Input.GetKeyDown( KeyCode.W ) && seciliItemIndex >= 0 && seciliItemIndex < itemBilgileri.Count ) scrollView.SrollToCell( seciliItemIndex, 10000f ); // E tuşuna basınca marketteki tüm eşyaları sil if( Input.GetKeyDown( KeyCode.E ) ) { itemBilgileri.Clear(); // Scroll View'daki tüm TestItem'ları temizle scrollView.ClearCells(); } } // Market için rastgele eşya verisi oluşturmaya yarar private ItemBilgileri RastgeleItemOlustur() { return new ItemBilgileri( "Item " + itemBilgileri.Count, Random.Range( 1, 1000 ) ); } // index'teki eşyanın TestItem'ı kameranın görüş alanına girdi; TestItem'ın içeriğini // o index'teki eşyanın verisini gösterecek şekilde güncelle private void ItemiGuncelle( LoopScrollRectItem i, int index ) { TestItem2 item = (TestItem2) i; // Isim ve Ucret Text'lerini güncelle item.isimText.text = itemBilgileri[index].isim; item.ucretText.text = itemBilgileri[index].ucret + " TL"; // Eğer seçili eşya bu eşya ise, TestItem'ın arkaplan rengini kırmızı yap (if), // değilse beyaz yap (else) if( index == seciliItemIndex ) item.arkaplan.color = new Color32( 230, 57, 70, 255 ); else item.arkaplan.color = new Color32( 241, 250, 238, 255 ); // Eğer bu TestItem için ItemiGuncelle fonksiyonu daha önce çağrılmadıysa if( item.itemYeniOlusturuldu ) { // Bu kodu sadece 1 kez çalıştır (aşağıdaki kodu birden çok kez çağırmak boş yere performansı etkiler) item.itemYeniOlusturuldu = false; // TestItem'a her tıklandığında (onClick) ItemeTiklandi fonksiyonunu çağır // Delegate'ler hakkında daha fazla bilgi için: https://yasirkula.com/2019/10/29/unity-c-delegate-ve-eventler/ item.buton.onClick.AddListener( () => ItemeTiklandi( item ) ); // Gerekirse TestItem'a rastgele yükseklik ver if( rastgeleItemYuksekligi ) item.layoutElement.preferredHeight = Random.Range( 100f, 200f ); } } // Bir TestItem'a tıklandı private void ItemeTiklandi( TestItem2 item ) { // Seçili eşya index'ini güncelle. TestItem'a atanan verinin index'ini // bulmak için CurrentRow değişkenini kullanmak yeterli seciliItemIndex = item.CurrentRow; // Kameranın görüş alanındaki tüm TestItem'ları güncelle (hepsi için ItemiGuncelle tekrar çağrılır) scrollView.RefreshCells(); } }
- kodda açıklanması gereken her yeri comment’lerle açıklamaya çalıştım. Özetle, oyunun başında LoopScrollRect objesinin ItemCallback‘ine kendi fonksiyonumuzu kaydediyoruz ve akabinde LoopScrollRect’e elimizdeki verinin kaç entry’den oluştuğunu totalCount ile söylüyoruz. Scroll View scroll oldukça, ItemCallback fonksiyonu yeni entry’ler için otomatik olarak çağrılıyor. Elimizdeki entry’lerin sayısı her değiştiğinde, bu değişikliği totalCount ile tekrardan LoopScrollRect’e bildiriyoruz. Elimizdeki tüm verileri temizlediğimizde, ClearCells fonksiyonu ile LoopScrollRect’i de temizliyoruz
- Loop Scroll Rect Test component’ini sahnenizdeki istediğiniz bir objeye verin. Component’teki Scroll View değişkenine değer olarak sahnedeki Scroll View objesini verin
- oyunu çalıştırın. Test amaçlı Q tuşu ile markete yeni eşyalar ekleyebilir, W tuşu ile seçili eşyaya odaklanabilir, E tuşu ile de marketteki tüm eşyaları silebilirsiniz
Böylece bu dersin sonuna geldik. Sonraki derslerde görüşmek üzere!
Hocam merhaba çok aradım bulamadım – sahnede obje kapalı ve o sahneyi unity de başlattığımda objenin aktif olmasını istiyorum bunu nasıl yapabilirim
Sahnede boş bir obje oluşturup ona verdiğiniz script’in Awake fonksiyonunda istediğiniz objeyi aktif hale getirebilirsiniz.
Hocam kusura bakmayın alakasız biraz ama ben Sizin Admob icin yazdığınız singelton scripti kullanıyorum. Sorum, Farklı scenelerde bannerın yerini nasıl ayarlayabilriz? Sizin yazdığınızda sadece bir tane secebiliyor gibiyiz?
instance’ı public yapıp ReklamScript.instance.bannerPozisyonu değişkenini değiştirdikten sonra, BannerReklamAl fonksiyonunu çağırmanız lazım.
Hocam Cok özür dileyerek anlamadığımı belirtmek isterim 😦
public static ReklamScript instance = null; 1.si bu heralde;
diğerlerini anlamadım ama.
ReklamScript.instance.bannerPozisyonu = blabla;
ReklamScript.BannerReklamAl();
Merhaba, peki bir şey sorabilir miyim? Farklı yüksekliklere sahip objelerle nasıl scroll oluşturabiliriz? Mesela konuşma baloncuğu mantığında bir şey… İlk baloncukta 1 cümle vardır yüksekliği 1 birimdir, İkincisinde -bir altında- 2 cümle vardır yüksekliği 2 birimdir gibi bir şey. Grid Layout, Horizontal Layout ve Vertical Layout componentlerinde bu işe yaramıyor.
LoopScrollRect plugin’i bunu destekliyor. LayoutElement’in Preferred Height değerini, ItemiGuncelle fonksiyonunda kodla değiştirebilirsiniz.