Bu codelab, Advanced Android in Kotlin kursunun bir parçasıdır. Bu kurstan en iyi şekilde yararlanmak için codelab'leri sırayla incelemeniz önerilir ancak bu zorunlu değildir. Kursla ilgili tüm codelab'ler Kotlin'de İleri Düzey Android codelab'leri açılış sayfasında listelenir.
Giriş
Bu codelab'in amacı doğrultusunda kırpma, bir resmin, tuvalin veya bit eşlemin, ekrana seçici olarak çizilen ya da çizilmeyen bölgelerini tanımlamanın bir yoludur. Kırpmanın amaçlarından biri fazla çizimi azaltmaktır. Aşırı çizim, ekrandaki bir pikselin son görüntüyü göstermek için birden fazla kez çizilmesidir. Aşırı çizimi azalttığınızda, çizim performansını en üst düzeye çıkarmak için bir pikselin veya ekran bölgesinin çizilme sayısını en aza indirirsiniz. Kullanıcı arayüzü tasarımında ve animasyonda ilginç efektler oluşturmak için kırpma özelliğini de kullanabilirsiniz.
Örneğin, aşağıdaki şekilde gösterildiği gibi üst üste binen bir kart destesi çizdiğinizde, her kartı alttan üste doğru tamamen çizmek yerine genellikle yalnızca görünen kısımları çizmek daha verimlidir. Kırpma işlemlerinin de bir maliyeti olduğundan ve genel olarak Android sistemi çok fazla çizim optimizasyonu yaptığından bu durum "genellikle" geçerlidir.

Kartların yalnızca görünür kısımlarını çizmek için her kart için bir kırpma bölgesi belirtirsiniz. Örneğin, aşağıdaki şemada bir resme kırpma dikdörtgeni uygulandığında yalnızca dikdörtgenin içindeki kısım gösterilir.

Kırpma bölgesi genellikle dikdörtgendir ancak metin de dahil olmak üzere herhangi bir şekil veya şekil kombinasyonu olabilir. Ayrıca, kırpma bölgesinin içindeki bölgenin dahil edilmesini veya hariç tutulmasını isteyip istemediğinizi de belirtebilirsiniz. Örneğin, dairesel bir kırpma bölgesi oluşturabilir ve yalnızca dairenin dışındaki öğeleri gösterebilirsiniz.
Bu codelab'de çeşitli kırpma yöntemlerini deneyeceksiniz.
Bilmeniz gerekenler
Aşağıdaki konular hakkında bilgi sahibi olmanız gerekir:
Activityiçeren bir uygulama oluşturma ve Android Studio'yu kullanarak çalıştırmaCanvasoluşturma ve üzerine çizim yapma- Özel
Viewoluşturma veonDraw()ileonSizeChanged()'ı geçersiz kılma.
Neler öğreneceksiniz?
- Nesneleri kırparak
Canvasüzerine çizim yapma - Tuvalin çizim durumlarını kaydetme ve geri yükleme
- Tuvale ve metne nasıl dönüşüm uygulanır?
Yapacaklarınız
- Kırpma işleminin farklı yöntemlerini ve bu yöntemlerin şekillerin görünürlüğü üzerindeki etkisini gösteren, kırpılmış şekilleri ekrana çizen bir uygulama oluşturun.
- Ayrıca, çevrilmiş ve çarpıtılmış metinler de çizeceksiniz.
ClippingExample uygulaması, bir tuvalin hangi bölümlerinin görünümde gösterileceğini belirtmek için şekilleri nasıl kullanıp birleştirebileceğinizi gösterir. Son uygulamanız aşağıdaki ekran görüntüsündeki gibi görünecektir.

Bu uygulamayı sıfırdan oluşturacağınız için bir proje oluşturmanız, boyutları ve dizeleri tanımlamanız ve bazı değişkenleri bildirmeniz gerekir.
1. adım: ClippingExample projesini oluşturun
- Empty Activity şablonunu kullanarak
ClippingExampleadlı bir Kotlin projesi oluşturun. Paket adı öneki içincom.example.androidkullanın. MainActivity.ktadlı kişiyi aç.onCreate()yönteminde, varsayılan içerik görünümünü değiştirin ve içerik görünümünüClippedViewöğesinin yeni bir örneği olarak ayarlayın. Bu görünüm, bir sonraki oluşturacağınız kırpma örnekleri için özel görünümünüz olur.
setContentView(ClippedView(this))MainActivity.ktile aynı düzeyde,View'ı genişletenClippedViewadlı özel bir görünüm için yeni bir Kotlin dosyası ve sınıfı oluşturun. Aşağıda gösterilen imzayı verin. Çalışmanızın geri kalanı buClippedViewiçinde yer alır.@JvmOverloadsek açıklaması, Kotlin derleyicisine bu işlev için varsayılan parametre değerlerinin yerine geçen aşırı yüklemeler oluşturmasını söyler.
class ClippedView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
}2. adım: Boyutları ve dize kaynaklarını ekleyin
- Kırpılmış görünümler için kullanacağınız boyutları
res/values/dimens.xmliçindeki yeni bir kaynak dosyasında tanımlayın. Bu varsayılan boyutlar sabit kodlanmıştır ve oldukça küçük bir ekrana sığacak şekilde boyutlandırılmıştır.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="clipRectRight">90dp</dimen>
<dimen name="clipRectBottom">90dp</dimen>
<dimen name="clipRectTop">0dp</dimen>
<dimen name="clipRectLeft">0dp</dimen>
<dimen name="rectInset">8dp</dimen>
<dimen name="smallRectOffset">40dp</dimen>
<dimen name="circleRadius">30dp</dimen>
<dimen name="textOffset">20dp</dimen>
<dimen name="strokeWidth">4dp</dimen>
<dimen name="textSize">18sp</dimen>
</resources>Uygulamanın daha büyük bir ekranda iyi görünmesi (ve ayrıntıların daha kolay görülmesi) için yalnızca daha büyük ekranlarda geçerli olan daha büyük değerlere sahip bir dimens dosyası oluşturabilirsiniz.
- Android Studio'da values klasörünü sağ tıklayın ve New > Values resource file'ı (Yeni > Değer kaynak dosyası) seçin.
- Yeni Kaynak Dosyası iletişim kutusunda dosyayı
dimensolarak adlandırın. Kullanılabilir niteleyiciler bölümünde En Küçük Ekran Genişliği'ni seçin ve >> düğmesini tıklayarak Seçilen niteleyiciler bölümüne ekleyin. En küçük ekran genişliği kutusuna 480 değerini girin ve Tamam'ı tıklayın.

- Dosya, değerler klasörünüzde aşağıda gösterildiği gibi görünmelidir.

- Dosyayı göremiyorsanız uygulamanın Proje Dosyaları görünümüne geçin. Yeni dosyanın tam yolu aşağıda gösterildiği gibidir:
ClippingExample/app/src/main/res/values-sw480dp/dimens.xml.

values-sw480dp/dimens.xmldosyasının varsayılan içeriğini aşağıdaki boyutlarla değiştirin.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="clipRectRight">120dp</dimen>
<dimen name="clipRectBottom">120dp</dimen>
<dimen name="rectInset">10dp</dimen>
<dimen name="smallRectOffset">50dp</dimen>
<dimen name="circleRadius">40dp</dimen>
<dimen name="textOffset">25dp</dimen>
<dimen name="strokeWidth">6dp</dimen>
</resources>strings.xmlbölümüne aşağıdaki dizeleri ekleyin. Bunlar, tuvalde metin görüntülemek için kullanılır.
<string name="clipping">Clipping</string>
<string name="translated">translated text</string>
<string name="skewed">"Skewed and "</string>3. adım: Paint ve Path nesnesi oluşturup başlatın
- Projenizin Android görünümüne geri dönün.
ClippedViewbölümünde, çizim yapmak için birPaintdeğişkeni tanımlayın. Kenar yumuşatma özelliğini etkinleştirin ve aşağıda gösterildiği gibi boyutlarda tanımlanan kontur genişliğini ve metin boyutunu kullanın.
private val paint = Paint().apply {
// Smooth out edges of what is drawn without affecting shape.
isAntiAlias = true
strokeWidth = resources.getDimension(R.dimen.strokeWidth)
textSize = resources.getDimension(R.dimen.textSize)
}ClippedViewiçinde, çizilenlerin yolunu yerel olarak depolamak için birPatholuşturup başlatın.android.graphics.Pathiçe aktarın.
private val path = Path()4. adım: Şekilleri ayarlayın
Bu uygulamada, çeşitli şekillerde kırpılmış birkaç satır ve iki sütun şekil gösteriyorsunuz.
Bu rollerin ortak özellikleri:
- Kapsayıcı görevi gören büyük bir dikdörtgen (kare)
- Büyük dikdörtgenin köşegen çizgisi
- Daire
- Kısa bir metin dizesi

Bu adımda, kaynaklardaki şekiller için boyutları ayarlarsınız. Böylece, bu şekilleri daha sonra kullandığınızda boyutları yalnızca bir kez almanız gerekir.
ClippedViewbölümünde,pathsimgesinin altında, şekil grubunun tamamını çevreleyen kırpma dikdörtgeninin boyutları için değişkenler ekleyin.
private val clipRectRight = resources.getDimension(R.dimen.clipRectRight)
private val clipRectBottom = resources.getDimension(R.dimen.clipRectBottom)
private val clipRectTop = resources.getDimension(R.dimen.clipRectTop)
private val clipRectLeft = resources.getDimension(R.dimen.clipRectLeft)- Dikdörtgenin iç kısmı ve küçük dikdörtgenin ofseti için değişkenler ekleyin.
private val rectInset = resources.getDimension(R.dimen.rectInset)
private val smallRectOffset = resources.getDimension(R.dimen.smallRectOffset)- Bir dairenin yarıçapı için değişken ekleyin. Bu, dikdörtgenin içine çizilen dairenin yarıçapıdır.
private val circleRadius = resources.getDimension(R.dimen.circleRadius)- Dikdörtgenin içine çizilen metin için bir ofset ve metin boyutu ekleyin.
private val textOffset = resources.getDimension(R.dimen.textOffset)
private val textSize = resources.getDimension(R.dimen.textSize)4. adım: Satır ve sütun konumlarını ayarlayın
Bu uygulamadaki şekiller, yukarıda ayarlanan boyutların değerlerine göre belirlenen iki sütun ve dört satır halinde gösterilir. Bu işlemin matematiksel kısmı bu codelab'de yer almamaktadır ancak bu adımda verilen kodu kopyalarken bu kısma göz atabilirsiniz.
- İki sütunun koordinatlarını ayarlayın.
private val columnOne = rectInset
private val columnTwo = columnOne + rectInset + clipRectRight- Dönüştürülmüş metnin son satırı da dahil olmak üzere her satırın koordinatlarını ekleyin.
private val rowOne = rectInset
private val rowTwo = rowOne + rectInset + clipRectBottom
private val rowThree = rowTwo + rectInset + clipRectBottom
private val rowFour = rowThree + rectInset + clipRectBottom
private val textRow = rowFour + (1.5f * clipRectBottom)- Uygulamanızı çalıştırın. Uygulama, adının altında boş beyaz bir ekranla açılmalıdır.

onDraw() içinde, aşağıdaki uygulama ekran görüntüsünde gösterildiği gibi yedi farklı kırpılmış dikdörtgen çizmek için yöntemleri çağırırsınız. Dikdörtgenlerin tümü aynı şekilde çizilir. Aralarındaki tek fark, tanımlanmış kırpma bölgeleri ve ekrandaki konumlarıdır.

Dikdörtgenleri çizmek için kullanılan algoritma, aşağıdaki şemada ve açıklamada gösterildiği gibi çalışır. Özetle, Canvas başlangıç noktasını hareket ettirerek bir dizi dikdörtgen çizersiniz. Kavramsal olarak bu işlem aşağıdaki adımlardan oluşur:

(1) Öncelikle Canvas öğesini dikdörtgenin çizilmesini istediğiniz yere çevirin. Yani, bir sonraki dikdörtgenin ve diğer tüm şekillerin nereye çizilmesi gerektiğini hesaplamak yerine Canvas başlangıç noktasını, yani koordinat sistemini taşırsınız.
(2) Ardından, tuvalin yeni başlangıç noktasında dikdörtgeni çizin. Yani, şekilleri çevrilmiş koordinat sisteminde aynı konuma çizersiniz. Bu yöntem çok daha basittir ve biraz daha verimlidir.
(3) Son olarak, Canvas öğesini orijinal Origin değerine geri yüklersiniz.
Uygulayacağınız algoritma şu şekildedir:
onDraw()içinde,Canvasöğesini gri arka plan rengiyle doldurmak ve orijinal şekilleri çizmek için bir işlev çağırın.- Kırpılmış her dikdörtgen ve çizilecek metin için bir işlev çağırın.
Her dikdörtgen veya metin için:
Canvasöğesinin mevcut durumunu kaydederek başlangıç durumuna sıfırlayabilirsiniz.- Tuvalin
Originkısmını çizim yapmak istediğiniz yere çevirin. - Kırpma şekilleri ve yolları uygulayın.
- Dikdörtgeni veya metni çizin.
Canvasdurumunu geri yükleyin.
Adım: onDraw() işlevini geçersiz kılın
- Aşağıdaki kodda gösterildiği gibi
onDraw()öğesini geçersiz kılın. Çizdiğiniz her şekil için daha sonra uygulayacağınız bir işlev çağırırsınız.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
drawBackAndUnclippedRectangle(canvas)
drawDifferenceClippingExample(canvas)
drawCircularClippingExample(canvas)
drawIntersectionClippingExample(canvas)
drawCombinedClippingExample(canvas)
drawRoundedRectangleClippingExample(canvas)
drawOutsideClippingExample(canvas)
drawSkewedTextExample(canvas)
drawTranslatedTextExample(canvas)
// drawQuickRejectExample(canvas)
}- Kodun derlenmeye devam etmesi için çizim işlevlerinin her biri için sap oluşturun. Aşağıdaki kodu kopyalayabilirsiniz.
private fun drawBackAndUnclippedRectangle(canvas: Canvas){
}
private fun drawDifferenceClippingExample(canvas: Canvas){
}
private fun drawCircularClippingExample(canvas: Canvas){
}
private fun drawIntersectionClippingExample(canvas: Canvas){
}
private fun drawCombinedClippingExample(canvas: Canvas){
}
private fun drawRoundedRectangleClippingExample(canvas: Canvas){
}
private fun drawOutsideClippingExample(canvas: Canvas){
}
private fun drawTranslatedTextExample(canvas: Canvas){
}
private fun drawSkewedTextExample(canvas: Canvas){
}
private fun drawQuickRejectExample(canvas: Canvas){
}Uygulama, aynı dikdörtgeni ve şekilleri yedi kez çizer. İlkinde kırpma uygulanmaz, diğer altı çizimde ise çeşitli kırpma yolları uygulanır. drawClippedRectangle() yöntemi, aşağıdaki örnekte gösterildiği gibi bir dikdörtgen çizme kodunu faktörize eder.

1. adım: drawClippedRectangle() yöntemini oluşturun
drawClippedRectangle()türünde bir bağımsız değişken alancanvasyöntemi oluşturun.Canvas
private fun drawClippedRectangle(canvas: Canvas) {
}drawClippedRectangle()yönteminin içinde, kırpma dikdörtgeninin sınırlarını şeklin tamamı için ayarlayın. Yalnızca kareyi çizecek şekilde kısıtlayan bir kırpma dikdörtgeni uygulayın.
canvas.clipRect(
clipRectLeft,clipRectTop,
clipRectRight,clipRectBottom
)Canvas.clipRect(...) yöntemi, gelecekteki çizim işlemlerinin yazılabileceği ekran bölgesini azaltır. Kırpma sınırlarını, geçerli kırpma dikdörtgeninin ve clipRect()'ya iletilen dikdörtgenin uzamsal kesişimi olarak ayarlar. Bölgeler için farklı biçimleri kabul eden ve kırpma dikdörtgeninde farklı işlemlere izin veren birçok clipRect() yöntemi varyantı vardır.
canvassimgesini beyaz renkle doldurun. Evet! Dikdörtgen çizmediğiniz, kırpma işlemi yaptığınız için tuvalin tamamı. Kırpma dikdörtgeni nedeniyle yalnızca kırpma dikdörtgeniyle tanımlanan bölge doldurulur ve beyaz bir dikdörtgen oluşturulur. Yüzeyin geri kalanı gri renkte kalır.
canvas.drawColor(Color.WHITE)- Rengi kırmızı olarak değiştirin ve kırpma dikdörtgeninin içine çapraz bir çizgi çizin.
paint.color = Color.RED
canvas.drawLine(
clipRectLeft,clipRectTop,
clipRectRight,clipRectBottom,paint
)- Rengi yeşil olarak ayarlayın ve kırpma dikdörtgeninin içine bir daire çizin.
paint.color = Color.GREEN
canvas.drawCircle(
circleRadius,clipRectBottom - circleRadius,
circleRadius,paint
)- Rengi mavi olarak ayarlayın ve kırpma dikdörtgeninin sağ kenarıyla hizalanmış metin çizin. Metin çizmek için
canvas.drawText()simgesini kullanın.
paint.color = Color.BLUE
// Align the RIGHT side of the text with the origin.
paint.textSize = textSize
paint.textAlign = Paint.Align.RIGHT
canvas.drawText(
context.getString(R.string.clipping),
clipRectRight,textOffset,paint
)2. adım: drawBackAndUnclippedRectangle() yöntemini uygulayın
drawClippedRectangle()yönteminin nasıl çalıştığını görmek için aşağıdaki gibidrawClippedRectangle()yöntemini uygulayarak ilk kırpılmamış dikdörtgeni çizin.drawBackAndUnclippedRectangle()canvasöğesini kaydedin, ilk satır ve sütun konumuna çevirin,drawClippedRectangle()öğesini çağırarak çizin ve ardındancanvasöğesini önceki durumuna geri yükleyin.
private fun drawBackAndUnclippedRectangle(canvas: Canvas){
canvas.drawColor(Color.GRAY)
canvas.save()
canvas.translate(columnOne,rowOne)
drawClippedRectangle(canvas)
canvas.restore()
}- Uygulamanızı çalıştırın. Gri arka plan üzerinde daire, kırmızı çizgi ve metin içeren ilk beyaz dikdörtgeni görmeniz gerekir.

Aşağıdaki kırpma örneğinde, grafik efektleri elde etmek için çeşitli kırpma bölgesi kombinasyonlarını nasıl uygulayacağınızı ve ihtiyacınız olan şekilleri oluşturmak için kırpma bölgelerini nasıl birleştirebileceğinizi öğreneceksiniz.
Bu yöntemlerin her biri aynı kalıbı izler.
- Tuvalin mevcut durumunu kaydetme:
canvas.save()
Etkinlik bağlamı, çizim durumlarının yığınını tutar. Çizim durumları, geçerli dönüşüm matrisinden ve geçerli kırpma bölgesinden oluşur. Mevcut durumu kaydedebilir, çizim durumunu değiştiren işlemler (ör. tuvali çevirme veya döndürme) yapabilir ve ardından kaydedilen çizim durumunu geri yükleyebilirsiniz. (Not: Bu, Git'teki "stash" komutuna benzer.)
Çiziminizde dönüştürmeler varsa dönüştürmeleri tersine çevirerek zincirleme ve geri alma işlemleri hataya açık olur. Örneğin, çevirme, uzatma ve döndürme işlemlerini sırayla yaptığınızda işlemler hızla karmaşıklaşır. Bunun yerine, tuvalin durumunu kaydedin, dönüşümlerinizi uygulayın, çizin ve ardından önceki durumu geri yükleyin.
Örneğin, bir kırpma bölgesi tanımlayıp bu durumu kaydedebilirsiniz. Ardından tuvali çevirin, kırpma bölgesi ekleyin ve döndürün. Çizim yaptıktan sonra orijinal kırpma durumunu geri yükleyebilir ve şemada gösterildiği gibi farklı bir çeviri ve çarpıtma dönüşümü yapmaya devam edebilirsiniz.

- Tuvalin başlangıç noktasını satır/sütun koordinatlarına çevirin:
canvas.translate()
Tuvalin başlangıç noktasını taşımak ve aynı şeyi yeni bir koordinat sisteminde çizmek, çizilecek tüm öğeleri taşımaktan çok daha kolaydır. (İpucu: Öğeleri döndürmek için de aynı tekniği kullanabilirsiniz.)
pathiçin varsa dönüşümleri uygulayın.- Kırpmayı uygula:
canvas.clipPath(path) - Şekilleri çizin:
drawClippedRectangle() or drawText() - Önceki tuval durumunu geri yükleme:
canvas.restore()
1. adım: drawDifferenceClippingExample(canvas) işlevini uygulayın
İki kırpma dikdörtgeni arasındaki farkı kullanarak resim çerçevesi efekti oluşturmak için ikinci dikdörtgeni çizecek kodu ekleyin.

Aşağıdaki işlemleri yapan kodu kullanın:
- Kanvası kaydedin.
- Tuvalin başlangıç noktasını, ilk satırın ikinci sütununda, ilk dikdörtgenin sağındaki açık alana çevirin.
- İki kırpma dikdörtgeni uygulayın.
DIFFERENCEoperatörü, ikinci dikdörtgeni birinciden çıkarır.
- Değiştirilmiş tuvali çizmek için
drawClippedRectangle()yöntemini çağırın. - Tuval durumunu geri yükleyin.
private fun drawDifferenceClippingExample(canvas: Canvas) {
canvas.save()
// Move the origin to the right for the next rectangle.
canvas.translate(columnTwo,rowOne)
// Use the subtraction of two clipping rectangles to create a frame.
canvas.clipRect(
2 * rectInset,2 * rectInset,
clipRectRight - 2 * rectInset,
clipRectBottom - 2 * rectInset
)
// The method clipRect(float, float, float, float, Region.Op
// .DIFFERENCE) was deprecated in API level 26. The recommended
// alternative method is clipOutRect(float, float, float, float),
// which is currently available in API level 26 and higher.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O){
canvas.clipRect(
4 * rectInset,4 * rectInset,
clipRectRight - 4 * rectInset,
clipRectBottom - 4 * rectInset,
Region.Op.DIFFERENCE
)
} else {
canvas.clipOutRect(
4 * rectInset,4 * rectInset,
clipRectRight - 4 * rectInset,
clipRectBottom - 4 * rectInset
)
}
drawClippedRectangle(canvas)
canvas.restore()
}- Uygulamanızı çalıştırdığınızda aşağıdaki gibi görünmelidir.

2. adım: drawCircularClippingExample(canvas) işlevini uygulayın
Ardından, dairesel bir yoldan oluşturulan dairesel kırpma bölgesini kullanan bir dikdörtgen çizmek için kod ekleyin. Bu işlem, daireyi kaldırarak (çizmeyerek) gri arka planı gösterir.

private fun drawCircularClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnOne, rowTwo)
// Clears any lines and curves from the path but unlike reset(),
// keeps the internal data structure for faster reuse.
path.rewind()
path.addCircle(
circleRadius,clipRectBottom - circleRadius,
circleRadius,Path.Direction.CCW
)
// The method clipPath(path, Region.Op.DIFFERENCE) was deprecated in
// API level 26. The recommended alternative method is
// clipOutPath(Path), which is currently available in
// API level 26 and higher.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
canvas.clipPath(path, Region.Op.DIFFERENCE)
} else {
canvas.clipOutPath(path)
}
drawClippedRectangle(canvas)
canvas.restore()
}3. adım: drawIntersectionClippingExample(canvas) işlevini uygulayın
Ardından, ikinci satır ve sütunda iki kırpma dikdörtgeninin kesişimini çizmek için kod ekleyin.


Ekran çözünürlüğünüze bağlı olarak bu bölgenin görünümünün değişeceğini unutmayın. Görünür bölgenin boyutunu değiştirmek için smallRectOffset boyutuyla denemeler yapın. Daha küçük bir smallRectOffset değeri, ekranda daha büyük bir bölgeye karşılık gelir.
private fun drawIntersectionClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnTwo,rowTwo)
canvas.clipRect(
clipRectLeft,clipRectTop,
clipRectRight - smallRectOffset,
clipRectBottom - smallRectOffset
)
// The method clipRect(float, float, float, float, Region.Op
// .INTERSECT) was deprecated in API level 26. The recommended
// alternative method is clipRect(float, float, float, float), which
// is currently available in API level 26 and higher.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
canvas.clipRect(
clipRectLeft + smallRectOffset,
clipRectTop + smallRectOffset,
clipRectRight,clipRectBottom,
Region.Op.INTERSECT
)
} else {
canvas.clipRect(
clipRectLeft + smallRectOffset,
clipRectTop + smallRectOffset,
clipRectRight,clipRectBottom
)
}
drawClippedRectangle(canvas)
canvas.restore()
}
4. adım: drawCombinedClippingExample(canvas) işlevini uygulayın
Ardından, bir daire ve bir dikdörtgen olmak üzere şekilleri birleştirin ve kırpma bölgesini tanımlamak için herhangi bir yol çizin.

private fun drawCombinedClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnOne, rowThree)
path.rewind()
path.addCircle(
clipRectLeft + rectInset + circleRadius,
clipRectTop + circleRadius + rectInset,
circleRadius,Path.Direction.CCW
)
path.addRect(
clipRectRight / 2 - circleRadius,
clipRectTop + circleRadius + rectInset,
clipRectRight / 2 + circleRadius,
clipRectBottom - rectInset,Path.Direction.CCW
)
canvas.clipPath(path)
drawClippedRectangle(canvas)
canvas.restore()
}
5. adım: drawRoundedRectangleClippingExample(canvas) işlevini uygulayın
Ardından, yaygın olarak kullanılan bir kırpma şekli olan yuvarlak bir dikdörtgen ekleyin.

- En üst düzeyde bir dikdörtgen değişkeni oluşturun ve başlatın.
RectF, kayan noktalı dikdörtgen koordinatlarını içeren bir sınıftır.
private var rectF = RectF(
rectInset,
rectInset,
clipRectRight - rectInset,
clipRectBottom - rectInset
)drawRoundedRectangleClippingExample()işlevini uygulayın.addRoundRect()işlevi bir dikdörtgen, köşe yarıçapının x ve y değerleri ve yuvarlak dikdörtgenin konturunu sarma yönünü alır.Path.Direction, kapalı şekillerin (ör. dikdörtgenler, ovaller) bir yola eklendiğinde nasıl yönlendirileceğini belirtir.CCW, saat yönünün tersine anlamına gelir.
private fun drawRoundedRectangleClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnTwo,rowThree)
path.rewind()
path.addRoundRect(
rectF,clipRectRight / 4,
clipRectRight / 4, Path.Direction.CCW
)
canvas.clipPath(path)
drawClippedRectangle(canvas)
canvas.restore()
}
6. adım: drawOutsideClippingExample(canvas) işlevini uygulayın
Kırpma dikdörtgeninin iç kısımlarını ikiye katlayarak dikdörtgenin etrafındaki dış kısmı kırpın.

private fun drawOutsideClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnOne,rowFour)
canvas.clipRect(2 * rectInset,2 * rectInset,
clipRectRight - 2 * rectInset,
clipRectBottom - 2 * rectInset)
drawClippedRectangle(canvas)
canvas.restore()
}
7. adım: drawTranslatedTextExample(canvas) işlevini uygulayın
Çizim metni, diğer şekillerden pek farklı değildir ve metne dönüştürme uygulayabilirsiniz. Örneğin, tuvali çevirip metni çizerek metin çevirebilirsiniz.

- Aşağıdaki işlevi uygulayın.
private fun drawTranslatedTextExample(canvas: Canvas) {
canvas.save()
paint.color = Color.GREEN
// Align the RIGHT side of the text with the origin.
paint.textAlign = Paint.Align.LEFT
// Apply transformation to canvas.
canvas.translate(columnTwo,textRow)
// Draw text.
canvas.drawText(context.getString(R.string.translated),
clipRectLeft,clipRectTop,paint)
canvas.restore()
}- Çevrilmiş metni görmek için uygulamanızı çalıştırın.

8. adım: drawSkewedTextExample(canvas) işlevini uygulayın
Metni eğebilirsiniz. Yani çeşitli şekillerde bozulur.

- Aşağıdaki işlevi
ClippedViewiçinde oluşturun.
private fun drawSkewedTextExample(canvas: Canvas) {
canvas.save()
paint.color = Color.YELLOW
paint.textAlign = Paint.Align.RIGHT
// Position text.
canvas.translate(columnTwo, textRow)
// Apply skew transformation.
canvas.skew(0.2f, 0.3f)
canvas.drawText(context.getString(R.string.skewed),
clipRectLeft, clipRectTop, paint)
canvas.restore()
}- Çarpıtılmış metnin, çevrilmiş metinden önce çizildiğini görmek için uygulamanızı çalıştırın.

quickReject() Canvas yöntemi, tüm dönüşümler uygulandıktan sonra belirtilen bir dikdörtgenin veya yolun, şu anda görünür olan bölgelerin tamamen dışında kalıp kalmayacağını kontrol etmenize olanak tanır.
quickReject() yöntemi, daha karmaşık çizimler oluşturduğunuzda ve bunu mümkün olduğunca hızlı yapmanız gerektiğinde inanılmaz derecede faydalıdır. quickReject() ile hangi nesneleri hiç çizmeniz gerekmediğine verimli bir şekilde karar verebilirsiniz ve kendi kesişim mantığınızı yazmanız gerekmez.
- Dikdörtgen veya yol ekranda hiç görünmüyorsa
quickReject()yöntemitruedeğerini döndürür. Kısmi çakışmalar için kendi kontrolünüzü yapmanız gerekir. EdgeType, yalnızca en yakın piksele yuvarlama içinAA(Kenarları yumuşatma: Kenarları yuvarlayarak işleyin, çünkü kenarları yumuşatılmış olabilir) veyaBW(Siyah-Beyaz: Kenarları yalnızca en yakın piksel sınırına yuvarlayarak işleyin) olur.
quickReject()'nın çeşitli sürümleri vardır ve bunları dokümanlarda da bulabilirsiniz.
| quickReject |
| quickReject |
| quickReject |
Bu alıştırmada, metnin altına ve clipRect içine yeni bir satır çizeceksiniz.
- Öncelikle
quickReject()ile çakışan bir dikdörtgeninClipRectangleilequickReject()'yı çağırırsınız.clipRectBu nedenlequickReject()yanlış değerini döndürür,clipRectBLACKile doldurulur veinClipRectangledikdörtgeni çizilir.

- Ardından kodu değiştirin ve
quickReject()işlevininotInClipRectangleile çağırın.quickReject()artık doğru değerini döndürüyor,clipRectWHITEile dolduruluyor venotInClipRectangleçizilmiyor.

Karmaşık çizimleriniz olduğunda bu özellik, hangi şekillerin kırpma bölgesinin tamamen dışında olduğunu ve hangileri için ek hesaplamalar yapmanız ve çizim yapmanız gerekebileceğini (kırpma bölgesinin kısmen veya tamamen içinde oldukları için) hızlıca anlamanızı sağlar.
Adım: quickReject() ile deneme yapın
- En üst düzeyde, ek bir satırın y koordinatları için bir değişken oluşturun.
private val rejectRow = rowFour + rectInset + 2*clipRectBottomClippedViewdosyasına aşağıdakidrawQuickRejectExample()işlevini ekleyin.quickReject()kullanmak için bilmeniz gereken her şey kodu okuyarak öğrenebilirsiniz.
private fun drawQuickRejectExample(canvas: Canvas) {
val inClipRectangle = RectF(clipRectRight / 2,
clipRectBottom / 2,
clipRectRight * 2,
clipRectBottom * 2)
val notInClipRectangle = RectF(RectF(clipRectRight+1,
clipRectBottom+1,
clipRectRight * 2,
clipRectBottom * 2))
canvas.save()
canvas.translate(columnOne, rejectRow)
canvas.clipRect(
clipRectLeft,clipRectTop,
clipRectRight,clipRectBottom
)
if (canvas.quickReject(
inClipRectangle, Canvas.EdgeType.AA)) {
canvas.drawColor(Color.WHITE)
}
else {
canvas.drawColor(Color.BLACK)
canvas.drawRect(inClipRectangle, paint
)
}
canvas.restore()
}onDraw()içindedrawQuickRejectExample()çağrısının yorumunu kaldırın.- Uygulamanızı çalıştırdığınızda, doldurulmuş kırpma bölgesi olan siyah bir dikdörtgen ve
inClipRectanglebölümlerini görürsünüz. Bunun nedeni, iki dikdörtgenin çakışmasıdır. Bu nedenlequickReject(),falsedeğerini döndürür veinClipRectangleçizilir.

drawQuickRejectExample()içinde, koduquickReject()'yinotInClipRectangle.'ye karşı çalıştıracak şekilde değiştirin.quickReject()artıktruedeğerini döndürüyor ve kırpma bölgesi beyazla dolduruluyor.

Tamamlanmış codelab'in kodunu indirin.
$ git clone https://github.com/googlecodelabs/android-kotlin-drawing-clipping
Alternatif olarak, depoyu Zip dosyası olarak indirebilir, dosyayı açıp Android Studio'da açabilirsiniz.
- Bir etkinliğin
Context,Canvasiçin dönüşümleri ve kırpma bölgelerini koruyan bir durumu sürdürür. - Tuvalinizi çizmek ve orijinal durumuna döndürmek için
canvas.save()vecanvas.restore()simgelerini kullanın. - Bir tuvalde birden fazla şekil çizmek için konumlarını hesaplayabilir veya çizim yüzeyinizin başlangıç noktasını taşıyabilirsiniz (dönüştürebilirsiniz). İkincisi, tekrarlanan çizim dizileri için yardımcı yöntemler oluşturmayı kolaylaştırabilir.
- Kırpma bölgeleri herhangi bir şekil, şekil kombinasyonu veya yol olabilir.
- İhtiyacınız olan bölgeyi tam olarak elde etmek için kırpma bölgelerini ekleyebilir, çıkarabilir ve kesiştirebilirsiniz.
- Tuvali dönüştürerek metne dönüştürme uygulayabilirsiniz.
quickReject()Canvasyöntemi, belirtilen bir dikdörtgenin veya yolun şu anda görünür olan bölgelerin tamamen dışında kalıp kalmayacağını kontrol etmenize olanak tanır.
Udacity kursu:
Android geliştirici belgeleri:
CanvassınıfıBitmapsınıfıViewsınıfıPaintsınıfıBitmap.configyapılandırmalarıRegion.OpoperatörleriPathsınıfıCanvassınıfıBitmapsınıfıViewsınıfıPaintsınıfıBitmap.configyapılandırmalarıRegion.OpoperatörleriPathsınıfıandroid.graphicsgrafik araçlarıBitmap.ConfigCanvasyapılandırmaları- Canvas ve Çizilebilir Öğeler
- canvas.translate() işlevi ne yapar?
- Tuval bağlamı için save() ve restore() işlevlerini anlama
- clipping
- overdraw.
@JvmOverloads
Android çerçevesinin ekrana nasıl çizim yaptığıyla ilgili ayrıntılı bir açıklama için Grafik Mimarisi makale serisine de göz atın.
Bu bölümde, bir eğitmenin yönettiği kurs kapsamında bu codelab'i tamamlayan öğrenciler için olası ödevler listelenmektedir. Eğitmen, aşağıdakileri yapmalıdır:
- Gerekirse ödev atayın.
- Öğrencilere ev ödevi ödevlerini nasıl göndereceklerini bildirin.
- Ödevlere not verin.
Eğitmenler bu önerileri istedikleri kadar kullanabilir ve uygun olduğunu düşündükleri diğer ödevleri verebilirler.
Bu codelab'i kendi başınıza tamamlıyorsanız bilginizi test etmek için bu ödevleri kullanabilirsiniz.
Bu soruları yanıtlayın
1. Soru
Şekillerin çizilmesini verimli bir şekilde engellemek için hangi yöntemi çağırırsınız?
▢ excludeFromDrawing()
▢ quickReject()
▢ onDraw()
▢ clipRect()
2. Soru
Canvas.save() ve Canvas.restore() hangi bilgileri kaydeder ve geri yükler?
▢ Renk, çizgi genişliği vb.
▢ Yalnızca mevcut dönüşümler
▢ Geçerli dönüşümler ve kırpma bölgesi
▢ Yalnızca geçerli kırpma bölgesi
3. Soru
Paint.Align şunları belirtir:
▢ Aşağıdaki çizim şekillerini hizalama
▢ Metnin, başlangıç noktasının hangi tarafından çizildiği
▢ Kırpma bölgesinde nereye hizalandığı
▢ Metnin hangi tarafı kaynağa hizalanacak?
Bu kurstaki diğer codelab'lerin bağlantıları için Advanced Android in Kotlin codelab'lerinin açılış sayfasına bakın.