Özel Görünüm Oluşturma

Bu codelab, Kotlin'deki Gelişmiş Android kursuna dahildir. Codelab'ler sırasında sırayla çalıştığınızda bu kurstan en yüksek değeri elde edersiniz ancak zorunlu değildir. Tüm kurs codelab'leri Kotlin Codelab'de Gelişmiş Android açılış sayfasında listelenmiştir.

Giriş

Android; Button, TextView, EditText, ImageView, CheckBox veya RadioButton gibi çok sayıda View alt sınıfı sunar. Bu alt sınıfları kullanarak kullanıcı etkileşimini etkinleştiren ve uygulamanızda bilgi görüntüleyen bir kullanıcı arayüzü oluşturabilirsiniz. View alt sınıflarının hiçbiri ihtiyaçlarınızı karşılamıyorsa özel görünüm olarak bilinen bir View alt sınıfı oluşturabilirsiniz.

Özel bir görünüm oluşturmak için mevcut bir View alt sınıfını (ör. Button veya EditText) genişletebilir veya kendi View alt sınıfınızı oluşturabilirsiniz. View öğesini doğrudan genişleterek, View tarafından çizilecek onDraw() yöntemini geçersiz kılarak istediğiniz boyutta ve şekilde etkileşimli bir kullanıcı arayüzü öğesi oluşturabilirsiniz.

Bir özel görünüm oluşturduktan sonra, bu görünümü, TextView veya Button ile aynı şekilde etkinlik düzenlerinize ekleyebilirsiniz.

Bu derste, View bölümünü genişleterek sıfırdan nasıl özel görünüm oluşturabileceğiniz gösterilmektedir.

Bilmeniz gerekenler

  • Android Studio'yu kullanarak Etkinlik içeren bir uygulama oluşturma.

Neler öğreneceksiniz?

  • Özel görünüm oluşturmak için View'i genişletme.
  • Daire şeklinde özel bir görünüm çizme.
  • Özel görünümle kullanıcı etkileşimini işlemek için dinleyicileri kullanma.
  • Özel bir düzende düzen nasıl kullanılır?

Yapacaklarınız

  • Özel görünüm oluşturmak için View simgesini genişletin.
  • Özel görünümü çizim ve boyama değerleriyle ilk kullanıma hazırlayın.
  • Görünümü çizmek için onDraw() öğesini geçersiz kılın.
  • Özel görünümün davranışını sağlamak için işleyicileri kullanın.
  • Özel görünümü bir düzene ekleyin.

CustomFanController uygulaması, View sınıfını genişleterek özel görünüm alt sınıfının nasıl oluşturulacağını gösterir. Yeni alt sınıfın adı DialView.

Uygulama, kapalı (0), düşük (1), orta (2) ve yüksek (3) ayarlarına sahip, fiziksel bir fan kontrolüne benzeyen yuvarlak bir kullanıcı arayüzü öğesi görüntüler. Kullanıcı görünüme dokunduğunda seçim göstergesi bir sonraki konuma hareket eder: 0-1-2-3 ve tekrar 0. Ayrıca, seçim 1 veya daha fazlaysa görünümün dairesel bölümünün arka plan rengi griden yeşile döner (hayran gücünün açık olduğunu gösterir).

Görüntüleme sayısı, bir uygulamanın kullanıcı arayüzünün temel yapı taşlarıdır. View sınıfı, tipik bir Android uygulamasının kullanıcı arayüzünün gereksinimlerini karşılayan, kullanıcı arayüzü widget'ları olarak adlandırılan birçok alt sınıf sağlar.

Button ve TextView gibi kullanıcı arayüzü yapı taşları, View sınıfını genişleten alt sınıflardır. Zamandan ve geliştirme çabalarından tasarruf etmek için bu View alt sınıftan birini uzatabilirsiniz. Özel görünüm, üst öğesinin görünümünü ve davranışını devralır. Değişiklik yapmak istediğiniz görünümün davranışını veya özelliğini geçersiz kılabilirsiniz. Örneğin, özel bir görünüm oluşturmak için EditText öğesini genişletirseniz görünüm, EditText görünümü gibi davranır ancak metin giriş alanındaki metni temizleyen bir X düğmesi gibi özelleştirilebilir.

Özel bir görünüm elde etmek için EditText gibi herhangi bir View alt sınıfını genişletebilirsiniz. Bunu yapmak istediğiniz sonuca en yakın olanı seçin. Daha sonra, özel görünümü diğer tüm View alt sınıflarında olduğu gibi, özelliklere sahip bir XML öğesi olarak bir veya daha fazla düzende kullanabilirsiniz.

Kendi özel görünümünüzü sıfırdan oluşturmak için View sınıfının kendisini genişletin. Kodunuz, görünümün ve işlevselliğin tanımlanması için View yöntemleri geçersiz kılar. Kendi özel görünümünüzü oluşturmanın anahtarı, her boyut ve şekildeki kullanıcı arayüzü öğesinin tamamını ekrana çizmekten sorumlu olmanızdır. Button gibi mevcut bir görünümün alt sınıfını çizerseniz söz konusu sınıf sizin için çizimi yönetir. (Bu codelab'de daha sonra çizim yapmak hakkında daha fazla bilgi edineceksiniz.)

Özel bir görünüm oluşturmak için aşağıdaki genel adımları uygulayın:

  • View veya View alt sınıfı (Button ya da EditText gibi) uzatan özel bir görünüm sınıfı oluşturun.
  • Mevcut bir View alt sınıfını uzatırsanız, yalnızca değiştirmek istediğiniz görünümün davranışını veya yönlerini geçersiz kılabilirsiniz.
  • View sınıfını genişletirseniz özel görünümün şeklini çizin ve yeni sınıfta onDraw() ve onMeasure() gibi View yöntemlerini geçersiz kılarak görünümünü kontrol edin.
  • Kullanıcı etkileşimine yanıt vermek için kod ekleyin ve gerekirse özel görünümü yeniden çizin.
  • Özel görünüm sınıfını, etkinliğinizin XML düzeninde bir kullanıcı arayüzü widget'ı olarak kullanın. Ayrıca, farklı düzenlerde görünüm için özelleştirme sağlamak üzere özel görünüm özellikleri tanımlayabilirsiniz.

Bu görevde:

  • Özel görünüm için geçici yer tutucu olarak ImageView içeren bir uygulama oluşturun.
  • Özel görünümü oluşturmak için View simgesini genişletin.
  • Özel görünümü çizim ve boyama değerleriyle ilk kullanıma hazırlayın.

1. Adım: ImageView yer tutucusu içeren bir uygulama oluşturun

  1. Boş Etkinlik şablonunu kullanarak CustomFanController başlıklı bir Kotlin uygulaması oluşturun. Paket adının com.example.android.customfancontroller olduğundan emin olun.
  2. XML kodunu düzenlemek için Metin sekmesinde activity_main.xml uygulamasını açın.
  3. Mevcut TextView kodunu bu kodla değiştirin. Bu metin, özel görünüm için etkinlikte bir etiket görevi görür.
<TextView
       android:id="@+id/customViewLabel"
       android:textAppearance="@style/Base.TextAppearance.AppCompat.Display3"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:padding="16dp"
       android:textColor="@android:color/black"
       android:layout_marginStart="8dp"
       android:layout_marginEnd="8dp"
       android:layout_marginTop="24dp"
       android:text="Fan Control"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       app:layout_constraintTop_toTopOf="parent"/>
  1. Bu ImageView öğesini düzene ekleyin. Bu codelab'de oluşturacağınız özel görünüm için bir yer tutucudur.
<ImageView
       android:id="@+id/dialView"
       android:layout_width="200dp"
       android:layout_height="200dp"
       android:background="@android:color/darker_gray"
       app:layout_constraintTop_toBottomOf="@+id/customViewLabel"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       android:layout_marginLeft="8dp"
       android:layout_marginRight="8dp"
       android:layout_marginTop="8dp"/>
  1. Her iki kullanıcı arayüzü öğesinde dize ve boyut kaynaklarını çıkarın.
  2. Tasarım sekmesini tıklayın. Düzen aşağıdaki gibi görünmelidir:

2. Adım Özel görünüm sınıfınızı oluşturma

  1. DialView adında yeni bir Kotlin sınıfı oluşturun.
  2. Sınıf tanımını değiştirerek View süresini uzatın. İstendiğinde android.view.View içe aktarın.
  3. View simgesini, ardından kırmızı ampulü tıklayın. '@JvmOverloads' ifadesini kullanarak Android View oluşturucuları ekle'yi seçin. Android Studio, View sınıfından oluşturucuyu ekler. @JvmOverloads ek açıklaması, Kotlin derleyicisine bu işlev için varsayılan parametre değerlerinin yerini alacak aşırı yüklemeler oluşturma talimatı verir.
class DialView @JvmOverloads constructor(
   context: Context,
   attrs: AttributeSet? = null,
   defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
  1. İçe aktarma işlemlerinin hemen altında DialView sınıfı tanımının üst kısmında kullanılabilir fan hızlarını temsil eden bir üst düzey enum ekleyin. Değerlerin gerçek dizeler yerine dize kaynakları olması nedeniyle bu enum öğesinin Int türünde olduğunu unutmayın. Android Studio, bu değerlerin her birinde eksik dize kaynakları için hataları gösterir. Bu durumu daha sonraki bir adımda düzeltebilirsiniz.
private enum class FanSpeed(val label: Int) {
   OFF(R.string.fan_off),
   LOW(R.string.fan_low),
   MEDIUM(R.string.fan_medium),
   HIGH(R.string.fan_high);
}
  1. enum altında, bu sabit değerleri ekleyin. Bunları, arama göstergelerini ve etiketleri çizmenin bir parçası olarak kullanırsınız.
private const val RADIUS_OFFSET_LABEL = 30      
private const val RADIUS_OFFSET_INDICATOR = -35
  1. DialView sınıfının içinde, özel görünümü çizmek için ihtiyacınız olan birkaç değişkeni tanımlayın. İstenirse android.graphics.PointF öğesini içe aktarın.
private var radius = 0.0f                   // Radius of the circle.
private var fanSpeed = FanSpeed.OFF         // The active selection.
// position variable which will be used to draw label and indicator circle position
private val pointPosition: PointF = PointF(0.0f, 0.0f)
  • radius, dairenin mevcut yarıçapıdır. Bu değer, görünüm ekranda çizildiğinde ayarlanır.
  • fanSpeed Vantilatörün şu anki hızıdır. Bu, FanSpeed numaralandırmasındaki değerlerden biridir. Bu değer varsayılan olarak OFF değeridir.
  • Son olarakpostPosition, ekranda birkaç öğenin görünümünü çizmek için bir X,Y noktasıdır.

Asıl çizim adımının mümkün olduğunca hızlı çalışması için, bu değerler, görünüm gerçekten çizildiğinde değil, burada oluşturulur ve başlatılır.

  1. Ayrıca, DialView sınıf tanımının içinde birkaç temel stille bir Paint nesnesi başlatın. İstendiğinde android.graphics.Paint ve android.graphics.Typeface içe aktarın. Daha önce değişkenlerde olduğu gibi, bu stiller çizim adımını hızlandırmaya yardımcı olmak için burada başlatılır.
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
   style = Paint.Style.FILL
   textAlign = Paint.Align.CENTER
   textSize = 55.0f
   typeface = Typeface.create( "", Typeface.BOLD)
}
  1. res/values/strings.xml sayfasını açın ve fan hızları için dize kaynaklarını ekleyin:
<string name="fan_off">off</string>
<string name="fan_low">1</string>
<string name="fan_medium">2</string>
<string name="fan_high">3</string>

Özel görünüm oluşturduktan sonra bunu çizebilmeniz gerekir. EditText gibi bir View alt sınıfını genişlettiğinizde bu alt sınıf, görünümün özelliklerini ve özelliklerini tanımlar ve kendini ekrana çeker. Dolayısıyla, görünümü çizmek için kod yazmanız gerekmez. Görünümünüzü özelleştirmek için ana makinenin yöntemlerini geçersiz kılabilirsiniz.

Kendi görünümünüzü sıfırdan oluşturuyorsanız (View uzatarak) ekran her yenilendiğinde tüm görünümü çizmek ve çizimi işleyen View yöntemlerini geçersiz kılmak sizin sorumluluğunuzdadır. View uzantısına sahip özel görünümü doğru şekilde çizmek için şunları yapmanız gerekir:

  • onSizeChanged() yöntemini geçersiz kılarak görünümün ilk olarak ne zaman göründüğünü ve boyutunu her değiştirdiğinizde hesaplama yapın.
  • Özel görünümü çizmek için onDraw() nesnesinin stiline sahip bir Canvas nesnesi kullanarak onDraw() yöntemini geçersiz kılın.
  • Bir kullanıcı tıklamasına yanıt verirken, görünümün tamamını geçersiz kılmak için görünümünü değiştirecek şekilde değiştirilen invalidate() yöntemini çağırın. Bu sayede görünümü yeniden çizmek için onDraw() çağrısı yapmak zorunda kalırsınız.

Ekran her yenilendiğinde onDraw() yöntemi çağrılır. Bu, saniyede birkaç kez yapılabilir. Performans nedenlerinden dolayı ve görsel hatalardan kaçınmak için onDraw() ürününde mümkün olduğunca az çalışmanız gerekir. Özellikle ayırmalar, görsel olarak takılmaya neden olabilecek çöp toplama işlemine neden olabileceğinden onDraw() içinde ayırmayın.

Canvas ve Paint sınıfları çeşitli yararlı çizim kısayolları sunar:

Daha sonraki bir codelab'de Canvas ve Paint hakkında daha fazla bilgi edineceksiniz. Android'in nasıl görüntüleme çektiği hakkında daha fazla bilgi edinmek için Android'in Görüntülemeleri Nasıl Çizdiği konusuna bakın.

Bu görevde onSizeChanged() ve onDraw() yöntemlerini kullanarak kumandanın özel görünümünü (kadranın kendisi, mevcut konum göstergesi ve gösterge etiketleri) ekrana çizersiniz. Ayrıca, kadranın üzerindeki gösterge etiketinin geçerli X,Y konumunu hesaplamak için yardımcı bir yöntem (computeXYForSpeed(),) oluşturacaksınız.

1. Adım: Konumları hesaplama ve görünümü çizme

  1. DialView sınıfında, başlatmaların altında View sınıfının onSizeChanged() yöntemini geçersiz kılarak özel görünüm aramasının boyutunu hesaplayın. kotlin aktarın.İstekte bulunulduğunda math.min.

    onSizeChanged() yöntemi, görünüm şişirildiğinde ilk kez çizildiği zaman da dahil olmak üzere görünümün boyutu her değiştiğinde çağrılır. Her çizimde yeniden hesaplamak yerine konumların, boyutların ve özel görünümünüzün boyutuyla ilgili diğer değerleri hesaplamak için onSizeChanged() değerini geçersiz kılın. Bu durumda, numaranın çember öğesinin geçerli yarıçapını hesaplamak için onSizeChanged() değerini kullanırsınız.
override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
   radius = (min(width, height) / 2.0 * 0.8).toFloat()
}
  1. onSizeChanged() altına, PointF sınıfı için bir computeXYForSpeed() uzantı işlevi tanımlamak üzere bu kodu ekleyin. İstendiğinde kotlin.math.cos ve kotlin.math.sin içe aktarın. PointF sınıfındaki bu uzantı işlevi, mevcut FanSpeed konumu ve yarıçapın yarıçapına göre metin etiketi ve geçerli gösterge (0, 1, 2 veya 3) için ekrandaki X, Y koordinatlarını hesaplar. Bunu onDraw(). içinde kullanacaksınız
private fun PointF.computeXYForSpeed(pos: FanSpeed, radius: Float) {
   // Angles are in radians.
   val startAngle = Math.PI * (9 / 8.0)   
   val angle = startAngle + pos.ordinal * (Math.PI / 4)
   x = (radius * cos(angle)).toFloat() + width / 2
   y = (radius * sin(angle)).toFloat() + height / 2
}
  1. Ekranda görünümü Canvas ve Paint sınıflarıyla oluşturmak için onDraw() yöntemini geçersiz kılın. İstendiğinde android.graphics.Canvas içe aktarın. Bu, iskeletin geçersiz kılınmasıdır:
override fun onDraw(canvas: Canvas) {
   super.onDraw(canvas)
   
}
  1. Fan hızının OFF veya başka herhangi bir değer olmasına göre boya rengini griye (Color.GRAY) ya da yeşile (Color.GREEN) ayarlamak için onDraw() içinde bu satırı ekleyin. İstendiğinde android.graphics.Color içe aktarın.
// Set dial background color to green if selection not off.
paint.color = if (fanSpeed == FanSpeed.OFF) Color.GRAY else Color.GREEN
  1. Arama için drawCircle() yöntemiyle daire çizmek üzere bu kodu ekleyin. Bu yöntem, dairenin merkezini, yarıçapını ve geçerli boya rengini bulmak için geçerli görünüm genişliğini ve yüksekliğini kullanır. width ve height özellikleri, View üst sınıfının üyeleridir ve görünümün mevcut boyutlarını belirtir.
// Draw the dial.
canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, paint)
  1. Bu kodu, fan hızı gösterge işaretiyle aynı şekilde daha küçük bir daire çizmek için drawCircle() yöntemini kullanarak ve bu bölümde PointF kullanın.Mevcut fan hızına göre gösterge merkezi için X,Y koordinatlarını hesaplamaya yönelik computeXYforSpeed() uzantı yöntemi.
// Draw the indicator circle.
val markerRadius = radius + RADIUS_OFFSET_INDICATOR
pointPosition.computeXYForSpeed(fanSpeed, markerRadius)
paint.color = Color.BLACK
canvas.drawCircle(pointPosition.x, pointPosition.y, radius/12, paint)
  1. Son olarak, fan hızı etiketlerini (0, 1, 2, 3) kadranın etrafında uygun konumlara çizin. Yöntemin bu bölümü, her bir etiketin konumunu almak için PointF.computeXYForSpeed() değerini tekrar çağırır ve ayırmaları önlemek için her seferinde pointPosition nesnesini yeniden kullanır. Etiketleri çizmek için drawText() simgesini kullanın.
// Draw the text labels.
val labelRadius = radius + RADIUS_OFFSET_LABEL
for (i in FanSpeed.values()) {
   pointPosition.computeXYForSpeed(i, labelRadius)
   val label = resources.getString(i.label)
   canvas.drawText(label, pointPosition.x, pointPosition.y, paint)
}

Tamamlanan onDraw() yöntemi şu şekilde görünür:

override fun onDraw(canvas: Canvas) {
   super.onDraw(canvas)
   // Set dial background color to green if selection not off.
   paint.color = if (fanSpeed == FanSpeed.OFF) Color.GRAY else Color.GREEN
   // Draw the dial.
   canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, paint)
   // Draw the indicator circle.
   val markerRadius = radius + RADIUS_OFFSET_INDICATOR
   pointPosition.computeXYForSpeed(fanSpeed, markerRadius)
   paint.color = Color.BLACK
   canvas.drawCircle(pointPosition.x, pointPosition.y, radius/12, paint)
   // Draw the text labels.
   val labelRadius = radius + RADIUS_OFFSET_LABEL
   for (i in FanSpeed.values()) {
       pointPosition.computeXYForSpeed(i, labelRadius)
       val label = resources.getString(i.label)
       canvas.drawText(label, pointPosition.x, pointPosition.y, paint)
   }
}

2. Adım: Görünümü düzene ekleyin

Bir uygulamanın kullanıcı arayüzüne özel bir görünüm eklemek için bunu etkinliğin XML düzeninde bir öğe olarak belirtirsiniz. Görünümünü ve davranışını, diğer kullanıcı arayüzü öğelerinde olduğu gibi XML öğesi özellikleriyle kontrol edin.

  1. activity_main.xml içinde dialView için ImageView etiketini com.example.android.customfancontroller.DialView olarak değiştirin ve android:background özelliğini silin. Hem DialView hem de orijinal ImageView, View sınıfındaki standart özellikleri devraldığı için diğer özelliklerin değiştirilmesine gerek yoktur. Yeni DialView öğesi şu şekilde görünür:
<com.example.android.customfancontroller.DialView
       android:id="@+id/dialView"
       android:layout_width="@dimen/fan_dimen"
       android:layout_height="@dimen/fan_dimen"
       app:layout_constraintTop_toBottomOf="@+id/customViewLabel"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       android:layout_marginLeft="@dimen/default_margin"
       android:layout_marginRight="@dimen/default_margin"
       android:layout_marginTop="@dimen/default_margin" />
  1. Uygulamayı çalıştırın. Fan kontrol görünümünüz etkinlikte görünür.

Son görev, kullanıcı görünüme dokunduğunda özel görünümünüzün işlem yapmasını sağlamaktır. Her dokunun, seçim göstergesini bir sonraki konuma taşımalıdır: Kapalı-1-2-3 ve tekrar kapalı. Ayrıca, seçim 1 veya daha fazlaysa arka plan griden yeşile döner, bu da fan gücünün açık olduğunu gösterir.

Özel görünümünüzün tıklanabilir olmasını sağlamak için:

  • Görünümün isClickable özelliğini true olarak ayarlayın. Bu sayede özel görünümünüz tıklamalara yanıt verebilir.
  • Görünüm tıklandığında işlem gerçekleştirmek için View sınıfın performClick() özelliğini uygulayın.
  • invalidate() yöntemini çağırın. Bu işlem, Android sistemine görünümü yeniden çizmek için onDraw() yöntemini çağırmasını söyler.

Normalde standart bir Android görünümünde kullanıcı bu görünümü tıkladığında işlem yapmak için OnClickListener() uygulanır. Özel bir görünüm için bunun yerine View sınıfının performClick() yöntemini uygular ve super yöntemini çağırırsınız.performClick(). Varsayılan performClick() yöntemi de onClickListener() çağırır. Dolayısıyla, işlemlerinizi performClick()'a ekleyebilir ve onClickListener() adlı çocuğun veya sizin özel görünümünüzü kullanabilecek diğer geliştiricilerin kullanabileceği şekilde özelleştirme imkanından yararlanmaya devam edebilirsiniz.

  1. DialView.kt için, FanSpeed sıralama özelliğinde, geçerli fan hızını listedeki bir sonraki hızla (OFF'den LOW'ye, MEDIUM ve HIGH'e, ardından tekrar OFF'ye değiştiren) bir uzantı işlevi ekleyin. Tam sıralama artık şu şekilde olacaktır:
private enum class FanSpeed(val label: Int) {
   OFF(R.string.fan_off),
   LOW(R.string.fan_low),
   MEDIUM(R.string.fan_medium),
   HIGH(R.string.fan_high);

   fun next() = when (this) {
       OFF -> LOW
       LOW -> MEDIUM
       MEDIUM -> HIGH
       HIGH -> OFF
   }
}
  1. DialView sınıfın içinde, onSizeChanged() yönteminden hemen önce bir init() bloku ekleyin. Görünümün isClickable özelliğinin true (doğru) değerine ayarlanması, bu görünümün kullanıcı girişini kabul etmesini sağlar.
init {
   isClickable = true
}
  1. init(), altında performClick() yöntemini aşağıdaki kodla geçersiz kılın.
override fun performClick(): Boolean {
   if (super.performClick()) return true

   fanSpeed = fanSpeed.next()
   contentDescription = resources.getString(fanSpeed.label)
  
   invalidate()
   return true
}

super numaralı telefona yapılan arama.Erişilebilirlik etkinliklerinin yanı sıra onClickListener() çağrılarına da olanak tanımak için öncelikle performClick() özelliğinin etkinleştirilmesi gerekir.

Sonraki iki satır, next() yöntemiyle fanın hızını artırır ve görünümün içerik açıklamasını geçerli hızı (kapalı, 1, 2 veya 3) temsil eden dize kaynağına ayarlayın.

Genel olarak, invalidate() yöntemi tüm görünümü geçersiz kılar ve onDraw() çağrısını yeniden yapmaya zorlar. Özel görünümünüzde kullanıcı etkileşimi de dahil olmak üzere herhangi bir nedenle bir değişiklik olursa ve değişikliğin gösterilmesi gerekiyorsa invalidate(). numaralı telefonu arayın

  1. Uygulamayı çalıştırın. Gösterge 1'den 1'e taşımak için DialView öğesine dokunun. Kadranın rengi yeşil olmalıdır. Her dokunuşla, gösterge bir sonraki konuma geçmelidir. gösterge kapandığında kadranın tekrar gri olması gerekir.

Bu örnekte, özel görünümünüzle özel özellikleri kullanmanın temel mekanizmaları gösterilmektedir. DialView sınıfı için özel özellikler, her hayran arama konumu için farklı bir renkle tanımlanır.

  1. res/values/attrs.xml sitesini oluşturup açın.
  2. <resources> içine bir <declare-styleable> kaynak öğesi ekleyin.
  3. <declare-styleable> kaynak öğesinin içinde, her özellik için bir name ve format içeren üç attr öğesi ekleyin. format bir türe benzer, bu durumda ise color şeklindedir.
<?xml version="1.0" encoding="utf-8"?>
<resources>
       <declare-styleable name="DialView">
           <attr name="fanColor1" format="color" />
           <attr name="fanColor2" format="color" />
           <attr name="fanColor3" format="color" />
       </declare-styleable>
</resources>
  1. activity_main.xml düzen dosyasını açın.
  2. DialView alanına fanColor1, fanColor2 ve fanColor3 için özellikler ekleyin ve değerlerini aşağıda gösterilen renklere ayarlayın. Özel özellikleriniz android ad alanı yerine schemas.android.com/apk/res/your_app_package_name ad alanına ait olduğundan, android: yerine özel özelliğin ön eki olarak app: kullanın (app:fanColor1 ile olduğu gibi).
app:fanColor1="#FFEB3B"
app:fanColor2="#CDDC39"
app:fanColor3="#009688"

DialView sınıfınızdaki özellikleri kullanabilmek için bunları almanız gerekir. Oluşturulduktan sonra sınıfınıza verilen bir AttributeSet içinde depolanır. Özellikleri init içinde alırsınız ve özellik değerlerini önbelleğe alma için yerel değişkenlere atarsınız.

  1. DialView.kt sınıf dosyasını açın.
  2. DialView içinde, özellik değerlerini önbelleğe almak için değişkenler bildirin.
private var fanSpeedLowColor = 0
private var fanSpeedMediumColor = 0
private var fanSeedMaxColor = 0
  1. init blokunda, withStyledAttributes uzantı işlevini kullanarak aşağıdaki kodu ekleyin. Özellikleri ve görünümleri sağlayıp yerel değişkenlerinizi ayarlarsınız. withStyledAttributes içe aktarıldığında doğru getColor() işlevi de içe aktarılır.
context.withStyledAttributes(attrs, R.styleable.DialView) {
   fanSpeedLowColor = getColor(R.styleable.DialView_fanColor1, 0)
   fanSpeedMediumColor = getColor(R.styleable.DialView_fanColor2, 0)
   fanSeedMaxColor = getColor(R.styleable.DialView_fanColor3, 0)
}
  1. Mevcut rengin fan hızına göre arama rengini ayarlamak için onDraw() bölümündeki yerel değişkenleri kullanın. Boya renginin ayarlandığı satırı (paint.color = if (fanSpeed == FanSpeed.OFF) Color.GRAY else Color.GREEN) aşağıdaki kodla değiştirin.
paint.color = when (fanSpeed) {
   FanSpeed.OFF -> Color.GRAY
   FanSpeed.LOW -> fanSpeedLowColor
   FanSpeed.MEDIUM -> fanSpeedMediumColor
   FanSpeed.HIGH -> fanSeedMaxColor
} as Int
  1. Uygulamanızı çalıştırın, düğmeyi tıklayın ve aşağıda gösterildiği gibi renk ayarı her konum için farklı olmalıdır.

Özel görünüm özellikleri hakkında daha fazla bilgi edinmek için Görünüm Sınıfı Oluşturma başlıklı makaleyi inceleyin.

Erişilebilirlik, uygulamanızın engelli kişiler de dahil olmak üzere herkes tarafından kullanılabilmesini sağlayan bir tasarım, uygulama ve test teknikleri grubudur.

Kişinin Android cihazını etkileyebilecek yaygın engellilik durumu; körlük, az görme, renk körlüğü, sağırlık veya işitme kaybı ve kısıtlı motor becerilerdir. Uygulamalarınızı, erişilebilirliklerini göz önünde bulundurarak geliştirdiğinizde, kullanıcı deneyimini yalnızca engelli kullanıcılar için değil, diğer tüm kullanıcılarınız için de daha iyi hale getirirsiniz.

Android, TextView ve Button gibi standart kullanıcı arayüzü görünümlerinde varsayılan olarak çeşitli erişilebilirlik özellikleri sağlar. Ancak özel bir görünüm oluştururken, bu özel görünümün ekrandaki içeriğin sözlü açıklamaları gibi erişilebilir özellikleri nasıl sağlayacağını göz önünde bulundurmanız gerekir.

Bu görevde TalkBack, Android ekran okuyucu hakkında bilgi edinecek ve uygulamanızı, DialView özel görünümü için sesli ipuçları ve açıklamalar içerecek şekilde değiştireceksiniz.

1. Adım TalkBack'i keşfetme

TalkBack, Android'in yerleşik ekran okuyucusudur. Android, ekran öğelerini sesli olarak tanımladığı için TalkBack etkinken kullanıcı ekranı görmeden Android cihazıyla etkileşimde bulunabilir. Görme engelli kullanıcılar uygulamanızı kullanmak için TalkBack'e güvenebilirler.

Bu görevde ekran okuyucuların nasıl çalıştığını ve uygulamalarda nasıl gezineceğini anlamak için TalkBack'i etkinleştirirsiniz.

  1. Bir Android cihazda veya emülatörde Ayarlar > Erişilebilirlik > TalkBack'e gidin.
  2. TalkBack'i açmak için Açık/Kapalı açma/kapatma düğmesine dokunun.
  3. İzinleri onaylamak için Tamam'a dokunun.
  4. Yapmanız istenirse cihaz şifrenizi onaylayın. TalkBack'i ilk kez çalıştırıyorsanız bir eğitim başlatılır. (Eğitim eski cihazlarda kullanılamayabilir.)
  5. Gözlerinizi kapalı tutarak eğitimde gezinmek faydalı olabilir. Eğitimi gelecekte tekrar açmak için Ayarlar > Erişilebilirlik > TalkBack > Ayarlar > TalkBack eğitimini başlat bölümüne gidin.
  6. CustomFanController uygulamasını derleyip çalıştırın veya cihazınızdaki Genel Bakış ya da Son Kullanılanlar düğmesiyle açın. TalkBack açıkken uygulama adının yanı sıra TextView etiketi metninin de duyurulduğuna dikkat edin. Ancak DialView görünümüne dokunursanız görünümün durumu (arama için geçerli ayar) veya aktif hale getirmek için görünüme dokunduğunuzda gerçekleştirilecek işlem hakkında bilgi verilmez.

2. Adım: Çeviri etiketleri için içerik açıklamaları ekleyin

İçerik açıklamaları, uygulamanızdaki görüntülemelerin anlamını ve amacını açıklar. Bu etiketler, Android’in TalkBack özelliği gibi ekran okuyucuların her bir öğenin işlevini doğru bir şekilde tanımlamasına olanak tanır. ImageView gibi statik görünümler için içerik açıklamasını, düzen dosyasındaki görünüme contentDescription özelliğiyle ekleyebilirsiniz. Metin görünümleri (TextView ve EditText), görünümdeki metni otomatik olarak içerik açıklaması olarak kullanır.

Özel fan kontrolü görünümünde, geçerli fan ayarını belirtmek için görünüm her tıklandığında içerik açıklamasını dinamik olarak güncellemeniz gerekir.

  1. DialView sınıfının en altında, bağımsız değişken veya dönüş türü içermeyen bir updateContentDescription() işlevi tanımlayın.
fun updateContentDescription() {
}
  1. updateContentDescription() içinde özel görünümün contentDescription özelliğini, geçerli fan hızıyla ilişkili dize kaynağıyla (kapalı, 1, 2 veya 3) değiştirin. Bunlar, ekranda kadraja çizildiğinde onDraw() ile aynı etiketlerdir.
fun updateContentDescription() {
   contentDescription = resources.getString(fanSpeed.label)
}
  1. init() blokuna kadar ilerleyin ve bu blokun sonuna, updateContentDescription() numaralı telefona bir arama ekleyin. Bu işlem, görünüm başlatıldığında içerik açıklamasını başlatır.
init {
   isClickable = true
   // ...

   updateContentDescription()
}
  1. performClick() yönteminde updateContentDescription() aramasına invalidate() aramasından hemen önce başka bir arama ekleyin.
override fun performClick(): Boolean {
   if (super.performClick()) return true
   fanSpeed = fanSpeed.next()
   updateContentDescription()
   invalidate()
   return true
}
  1. Uygulamayı derleyip çalıştırın ve TalkBack'in açık olduğundan emin olun. Arama görünümü ayarını değiştirmek için TalkBack'in geçerli etiketi (kapalı, 1, 2, 3) ve "Etkinleştirmek için iki kez dokun" ifadesini duyurduğuna dikkat edin.

3. Adım: Tıklama işlemi için daha fazla bilgi ekleyin

Bu konumda durabilirsiniz. Görünümünüz TalkBack'te kullanılabilir. Ancak görünümünüz sadece etkinleştirilebilir etkinleştirilebileceğini belirtmekle ("&quot"Etkinleştirmek için iki kez dokunmak") değil, aynı zamanda görünüm etkinleştirildiğinde ne olacağını iki kez dokunarak değiştirmek veya dokunmak için iki kez dokunmak da yararlıdır.

Bunu yapmak için, bir erişilebilirlik yetkisi aracılığıyla bir erişilebilirlik düğümü bilgi nesnesine görüntüleme işlemi (burada bir tıklama veya dokunma işlemi) hakkında bilgi ekleyin. Erişilebilirlik yetkisi verme, uygulamanızın sözleşme yoluyla (devralmak yerine) erişilebilirlikle ilgili özelliklerini özelleştirmenize olanak tanır.

Bu görev için geriye dönük uyumluluk sağlamak amacıyla Android Jetpack kitaplıklarındaki (androidx.*) erişilebilirlik sınıflarını kullanacaksınız.

  1. DialView.kt blokunda, init blokunda yeni bir AccessibilityDelegateCompat nesnesi olarak görünüm için erişilebilirlik yetkisi belirleyin. İstendiğinde androidx.core.view.ViewCompat ve androidx.core.view.AccessibilityDelegateCompat içe aktarın. Bu strateji, uygulamanızda büyük ölçüde geriye dönük uyumluluk sağlar.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   
})
  1. AccessibilityDelegateCompat nesnesinin içinde onInitializeAccessibilityNodeInfo() işlevini AccessibilityNodeInfoCompat nesnesiyle geçersiz kılın ve süper yöntem yöntemini çağırın. İstendiğinde androidx.core.view.accessibility.AccessibilityNodeInfoCompat içe aktarın.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   override fun onInitializeAccessibilityNodeInfo(host: View, 
                            info: AccessibilityNodeInfoCompat) {
      super.onInitializeAccessibilityNodeInfo(host, info)

   }  
})

Her görünümde, görünümün gerçek düzen bileşenlerine karşılık gelebilen veya karşılık gelmeyen bir erişilebilirlik düğümü ağacı vardır. Android’in erişilebilirlik hizmetleri, görünüm hakkında bilgi (örneğin, sesli içerik açıklamaları veya ilgili görünümde gerçekleştirilebilecek olası işlemler) bulmak için bu düğümlerde gezinir. Özel bir görünüm oluşturduğunuzda, erişilebilirlik için özel bilgiler sağlamak üzere düğüm bilgilerini geçersiz kılmanız da gerekebilir. Bu durumda, düğüm bilgisinin, görüntüleme işlemi için özel bilgiler olduğunu geçersiz kılmasını sağlarsınız.

  1. onInitializeAccessibilityNodeInfo() içinde yeni bir AccessibilityNodeInfoCompat.AccessibilityActionCompat nesnesi oluşturun ve bunu customClick değişkenine atayın. Oluşturucu AccessibilityNodeInfo.ACTION_CLICK parametresine ve yer tutucu dizesine geçin. İstendiğinde AccessibilityNodeInfo içe aktarın.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   override fun onInitializeAccessibilityNodeInfo(host: View, 
                            info: AccessibilityNodeInfoCompat) {
      super.onInitializeAccessibilityNodeInfo(host, info)
      val customClick = AccessibilityNodeInfoCompat.AccessibilityActionCompat(
         AccessibilityNodeInfo.ACTION_CLICK,
        "placeholder"
      )
   }  
})

AccessibilityActionCompat sınıfı, erişilebilirlik amacıyla bir görünümle ilgili işlemi temsil eder. Tipik bir işlem, burada kullandığınız şekilde bir tıklama veya dokunmadır. Ancak diğer işlemlerde odağı kazanma veya kaybetme, bir pano işlemi (kesme/kopyalama/yapıştırma) ya da görünüm içinde kaydırma yer alabilir. Bu sınıfın oluşturucusu, işlem sabiti (burada, AccessibilityNodeInfo.ACTION_CLICK) ve TalkBack tarafından işlemin ne olduğunu belirtmek için kullanılan bir dizeyi gerektirir.

  1. Bir dize kaynağını almak için "placeholder" dizesini context.getString() çağrısıyla değiştirin. Belirli bir kaynak için mevcut fan hızını test edin. Şu anda hız FanSpeed.HIGH ise dize "Reset". Fan hızı başka bir değerse dize "Change." Bu dize kaynaklarını daha sonra oluşturacaksınız.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   override fun onInitializeAccessibilityNodeInfo(host: View, 
                            info: AccessibilityNodeInfoCompat) {
      super.onInitializeAccessibilityNodeInfo(host, info)
      val customClick = AccessibilityNodeInfoCompat.AccessibilityActionCompat(
         AccessibilityNodeInfo.ACTION_CLICK,
        context.getString(if (fanSpeed !=  FanSpeed.HIGH) R.string.change else R.string.reset)
      )
   }  
})
  1. customClick tanımı için kapanış parantezinden sonra, yeni erişilebilirlik işlemini düğüm bilgisi nesnesine eklemek için addAction() yöntemini kullanın.
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
   override fun onInitializeAccessibilityNodeInfo(host: View, 
                            info: AccessibilityNodeInfoCompat) {
       super.onInitializeAccessibilityNodeInfo(host, info)
       val customClick = AccessibilityNodeInfoCompat.AccessibilityActionCompat(
           AccessibilityNodeInfo.ACTION_CLICK,
           context.getString(if (fanSpeed !=  FanSpeed.HIGH) 
                                 R.string.change else R.string.reset)
       )
       info.addAction(customClick)
   }
})
  1. res/values/strings.xml öğesinde, "Change" ve "Sıfırla" için dize kaynaklarını ekleyin.
<string name="change">Change</string>
<string name="reset">Reset</string>
  1. Uygulamayı derleyip çalıştırın ve TalkBack'in açık olduğundan emin olun. Şimdi "Etkinleştirmek için iki kez dokun" ifadesinin "Değişmek için iki kez dokunun" (hayran hızının yüksek veya 3'ten az olması durumunda) ya da "Sıfırlamak için iki kez dokunun" (fabrika hızının zaten yüksek veya 3 olduğu durumlarda) olduğuna dikkat edin. "ve iki kez dokunun..." isteminin TalkBack hizmeti tarafından sağlandığını unutmayın.

Tamamlanan codelab'in kodunu indirin.

$  git clone https://github.com/googlecodelabs/android-kotlin-drawing-custom-views


Alternatif olarak, veri havuzunu Zip dosyası olarak indirip sıkıştırılmış dosyayı Android Studio'da açabilirsiniz.

Zip'i İndir

  • EditText gibi bir View alt sınıfının görünümünü ve davranışını devralan özel bir görünüm oluşturmak için bu alt sınıfı genişleten yeni bir sınıf ekleyin ve alt sınıfın bazı yöntemlerini geçersiz kılarak düzenlemeler yapın.
  • Her boyutta ve şekilde özel bir görünüm oluşturmak için yeni bir View sınıfı ekleyin.
  • Görünümün şeklini ve temel görünümünü tanımlamak için onDraw() gibi View yöntemlerini geçersiz kılın.
  • Görünümün çizimini veya çizimini zorunlu kılmak için invalidate() simgesini kullanın.
  • Performansı optimize etmek için değişkenleri ayırın ve çizim ve boyama için gerekli değerleri (ör. üye değişkenlerinin başlatılmasında) onDraw() politikasından önce atayın.
  • Görünümün etkileşimli davranışını sağlamak için özel görünüm için OnClickListener() yerine performClick() değerini geçersiz kılın. Bu işlem, sizin veya özel görünüm sınıfınızı kullanabilecek diğer Android geliştiricilerinin daha fazla davranış sağlamak için onClickListener() kullanmasına olanak tanır.
  • Özel görünümü, diğer kullanıcı arayüzü öğelerinde olduğu gibi görünümünü tanımlayan özelliklere sahip bir XML düzeni dosyasına ekleyin.
  • Özel özellikleri tanımlamak için values klasöründe attrs.xml dosyasını oluşturun. Ardından, XML düzeni dosyasında özel görünüm için özel özellikleri kullanabilirsiniz.

Udacity kursu:

Android geliştirici dokümanları:

Videolar:

Bu bölümde, bir eğitmen tarafından sunulan kurs kapsamında bu codelab üzerinden çalışan öğrenciler için olası ev ödevi ödevleri listelenmektedir. Öğretmenin şunları yapması gerekir:

  • Gerekirse ev ödevini atayın.
  • Öğrencilere ev ödevlerinin nasıl gönderileceğini bildirin.
  • Ev ödevlerine not verin.

Öğretmenler bu önerileri istedikleri kadar kullanabilir veya uygun görebilir ve uygun olan diğer ev ödevlerini atayabilirler.

Bu codelab'de kendiniz çalışıyorsanız, bilginizi test etmek için bu ödevlerden yararlanabilirsiniz.

1. Soru

Özel görünüme ilk kez bir boyut atandığında konumları, boyutları ve diğer değerleri hesaplamak için hangi yöntemi geçersiz kılarsınız?

makbuz onMeasure()

makbuz onSizeChanged()

makbuz invalidate()

makbuz onDraw()

2. Soru

Görünümünüzün onDraw() ile yeniden çizilmesini istediğinizi belirtmek için bir özellik değeri değiştikten sonra kullanıcı arayüzü ileti dizisinden hangi yöntemi çağırıyorsunuz?

▢ onMeasure()

▢ onSizeChanged()

▢ invalidate()

▢ getVisibility()

3. Soru

Özel görünümünüze etkileşim eklemek için hangi View yöntemini geçersiz kılmanız gerekir?

▢ setOnClickListener()

▢ onSizeChanged()

▢ isClickable()

▢ performClick()

Bu kurstaki diğer codelab'lerin bağlantıları için Kotlin codelab'lerdeki Gelişmiş Android açılış sayfasına bakın.