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
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
veyaView
alt sınıfı (Button
ya daEditText
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ıftaonDraw()
veonMeasure()
gibiView
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
- Boş Etkinlik şablonunu kullanarak
CustomFanController
başlıklı bir Kotlin uygulaması oluşturun. Paket adınıncom.example.android.customfancontroller
olduğundan emin olun. - XML kodunu düzenlemek için Metin sekmesinde
activity_main.xml
uygulamasını açın. - 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"/>
- 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"/>
- Her iki kullanıcı arayüzü öğesinde dize ve boyut kaynaklarını çıkarın.
- 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
DialView
adında yeni bir Kotlin sınıfı oluşturun.- Sınıf tanımını değiştirerek
View
süresini uzatın. İstendiğindeandroid.view.View
içe aktarın. 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) {
- İç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üzeyenum
ekleyin. Değerlerin gerçek dizeler yerine dize kaynakları olması nedeniyle buenum
öğesininInt
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);
}
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
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. İstenirseandroid.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 olarakOFF
değeridir.- Son olarak
postPosition
, 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.
- Ayrıca,
DialView
sınıf tanımının içinde birkaç temel stille birPaint
nesnesi başlatın. İstendiğindeandroid.graphics.Paint
veandroid.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)
}
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 birCanvas
nesnesi kullanarakonDraw()
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çinonDraw()
ç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:
drawText()
kullanarak metin çizin.setTypeface()
numaralı telefonu arayarak yazı tipini vesetColor()
ifadesini arayarak metin rengini belirtin.drawRect()
,drawOval()
vedrawArc()
kullanarak temel şekiller çizin.setStyle()
yöntemini çağırarak şekillerin dolu, anahatlı veya her ikisini birden değiştirin.drawBitmap()
kullanarak bit eşlem çizin.
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
DialView
sınıfında, başlatmaların altındaView
sınıfınınonSizeChanged()
yöntemini geçersiz kılarak özel görünüm aramasının boyutunu hesaplayın.kotlin
aktarın.İstekte bulunulduğundamath.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çinonSizeChanged()
değerini geçersiz kılın. Bu durumda, numaranın çember öğesinin geçerli yarıçapını hesaplamak içinonSizeChanged()
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()
}
onSizeChanged()
altına,PointF
sınıfı için bircomputeXYForSpeed()
uzantı işlevi tanımlamak üzere bu kodu ekleyin. İstendiğindekotlin.math.cos
vekotlin.math.sin
içe aktarın.PointF
sınıfındaki bu uzantı işlevi, mevcutFanSpeed
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. BunuonDraw().
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
}
- Ekranda görünümü
Canvas
vePaint
sınıflarıyla oluşturmak içinonDraw()
yöntemini geçersiz kılın. İstendiğindeandroid.graphics.Canvas
içe aktarın. Bu, iskeletin geçersiz kılınmasıdır:
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
}
- 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çinonDraw()
içinde bu satırı ekleyin. İstendiğindeandroid.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
- 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
veheight
ö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)
- 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ümdePointF
kullanın.Mevcut fan hızına göre gösterge merkezi için X,Y koordinatlarını hesaplamaya yönelikcomputeXYforSpeed()
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)
- 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 seferindepointPosition
nesnesini yeniden kullanır. Etiketleri çizmek içindrawText()
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.
activity_main.xml
içindedialView
içinImageView
etiketinicom.example.android.customfancontroller.DialView
olarak değiştirin veandroid:background
özelliğini silin. HemDialView
hem de orijinalImageView
,View
sınıfındaki standart özellikleri devraldığı için diğer özelliklerin değiştirilmesine gerek yoktur. YeniDialView
öğ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" />
- 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ğinitrue
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ınperformClick
()
özelliğini uygulayın. invalidate()
yöntemini çağırın. Bu işlem, Android sistemine görünümü yeniden çizmek içinonDraw()
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.
DialView.kt
için,FanSpeed
sıralama özelliğinde, geçerli fan hızını listedeki bir sonraki hızla (OFF
'denLOW
'ye,MEDIUM
veHIGH
'e, ardından tekrarOFF
'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
}
}
DialView
sınıfın içinde,onSizeChanged()
yönteminden hemen önce birinit()
bloku ekleyin. GörünümünisClickable
ö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
}
init(),
altındaperformClick()
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
- 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.
res/values/attrs.xml
sitesini oluşturup açın.<resources>
içine bir<declare-styleable>
kaynak öğesi ekleyin.<declare-styleable>
kaynak öğesinin içinde, her özellik için birname
veformat
içeren üçattr
öğesi ekleyin.format
bir türe benzer, bu durumda isecolor
ş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>
activity_main.xml
düzen dosyasını açın.DialView
alanınafanColor1
,fanColor2
vefanColor3
için özellikler ekleyin ve değerlerini aşağıda gösterilen renklere ayarlayın. Özel özelliklerinizandroid
ad alanı yerineschemas.android.com/apk/res/
your_app_package_name
ad alanına ait olduğundan,android:
yerine özel özelliğin ön eki olarakapp:
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.
DialView.kt
sınıf dosyasını açın.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
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ğrugetColor()
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)
}
- 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
- 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.
- Bir Android cihazda veya emülatörde Ayarlar > Erişilebilirlik > TalkBack'e gidin.
- TalkBack'i açmak için Açık/Kapalı açma/kapatma düğmesine dokunun.
- İzinleri onaylamak için Tamam'a dokunun.
- 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.)
- 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.
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ıraTextView
etiketi metninin de duyurulduğuna dikkat edin. AncakDialView
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.
DialView
sınıfının en altında, bağımsız değişken veya dönüş türü içermeyen birupdateContentDescription()
işlevi tanımlayın.
fun updateContentDescription() {
}
updateContentDescription()
içinde özel görünümüncontentDescription
ö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ğindeonDraw()
ile aynı etiketlerdir.
fun updateContentDescription() {
contentDescription = resources.getString(fanSpeed.label)
}
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()
}
performClick()
yöntemindeupdateContentDescription()
aramasınainvalidate()
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
}
- 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 ("""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.
DialView.kt
blokunda,init
blokunda yeni birAccessibilityDelegateCompat
nesnesi olarak görünüm için erişilebilirlik yetkisi belirleyin. İstendiğindeandroidx.core.view.ViewCompat
veandroidx.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() {
})
AccessibilityDelegateCompat
nesnesinin içindeonInitializeAccessibilityNodeInfo()
işleviniAccessibilityNodeInfoCompat
nesnesiyle geçersiz kılın ve süper yöntem yöntemini çağırın. İstendiğindeandroidx.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.
onInitializeAccessibilityNodeInfo()
içinde yeni birAccessibilityNodeInfoCompat.AccessibilityActionCompat
nesnesi oluşturun ve bunucustomClick
değişkenine atayın. OluşturucuAccessibilityNodeInfo.ACTION_CLICK
parametresine ve yer tutucu dizesine geçin. İstendiğindeAccessibilityNodeInfo
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.
- Bir dize kaynağını almak için
"placeholder"
dizesinicontext.getString()
çağrısıyla değiştirin. Belirli bir kaynak için mevcut fan hızını test edin. Şu anda hızFanSpeed.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)
)
}
})
customClick
tanımı için kapanış parantezinden sonra, yeni erişilebilirlik işlemini düğüm bilgisi nesnesine eklemek içinaddAction()
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)
}
})
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>
- 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.
EditText
gibi birView
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()
gibiView
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
() yerineperformClick()
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çinonClickListener()
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ündeattrs.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ı:
- Özel Görünüm Oluşturma
@JvmOverloads
- Özel Bileşenler
- Android Görüntülemeleri Nasıl Çeker?
onMeasure()
onSizeChanged()
onDraw()
Canvas
Paint
drawText()
setTypeface()
setColor()
drawRect()
drawOval()
drawArc()
drawBitmap()
setStyle()
invalidate()
- Görüntüle
- Giriş Etkinlikleri
- Boya
- Kotlin uzantı kitaplığı android-ktx
withStyledAttributes
- Android KTX dokümanları
- Android KTX orijinal duyuru blogu
- Özel görünümleri daha erişilebilir hale getirme
AccessibilityDelegateCompat
AccessibilityNodeInfoCompat
AccessibilityNodeInfoCompat.AccessibilityActionCompat
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.