Uygulamanızda statik resimler göstermeniz gerektiğinde şekil ve resim çizmek için Drawable sınıfını ve alt sınıflarını kullanabilirsiniz. Drawable, çizilebilen bir şeyin genel soyutlamasıdır. Çeşitli alt sınıflar, belirli resim senaryolarına yardımcı olur ve bunları, benzersiz şekilde davranan kendi çizilebilir nesnelerinizi tanımlamak için genişletebilirsiniz.
Sınıf oluşturucularını kullanmanın yanı sıra Drawable öğesini tanımlayıp örneklemenin iki yolu vardır:
- Projenize kaydedilmiş bir resim kaynağını (bitmap dosyası) büyütür.
- Çizilebilir özellikleri tanımlayan bir XML kaynağını genişletin.
Not: Bunun yerine, bir dizi nokta, çizgi ve eğri ile ilişkili renk bilgilerini kullanarak bir resmi tanımlayan drawable vektör öğesini kullanmayı tercih edebilirsiniz. Bu sayede, vektör çizilebilir öğeler kalite kaybı olmadan farklı boyutlarda ölçeklendirilebilir. Daha fazla bilgi için Vektör çizilebilir öğelerine genel bakış başlıklı makaleyi inceleyin.
Kaynak resimlerden çizilebilir öğeler oluşturma
Proje kaynaklarınızdaki bir resim dosyasına referans vererek uygulamanıza grafik ekleyebilirsiniz. Desteklenen dosya türleri PNG (tercih edilen), JPG (kabul edilen) ve GIF'tir (önerilmeyen). Uygulama simgeleri, logolar ve oyunlarda kullanılanlar gibi diğer grafikler bu teknik için uygundur.
Resim kaynağını kullanmak için dosyanızı projenizin res/drawable/
dizinine ekleyin. Projenizdeyken kodunuzdan veya XML düzeninizden resim kaynağına başvurabilirsiniz. Her iki durumda da, dosya türü uzantısı olmadan dosya adı olan bir kaynak kimliği kullanılarak başvurulur. Örneğin, my_image.png öğesini my_image olarak adlandırın.
Not: res/drawable/ dizinine yerleştirilen resim kaynakları, derleme işlemi sırasında aapt aracı tarafından kayıpsız resim sıkıştırma ile otomatik olarak optimize edilebilir. Örneğin, 256'dan fazla renk gerektirmeyen gerçek renkli bir PNG, renk paleti içeren 8 bitlik bir PNG'ye dönüştürülebilir. Bu, eşit kalitede ancak daha az bellek gerektiren bir görüntüyle sonuçlanır. Bu nedenle, bu dizine yerleştirilen resim ikilileri derleme sırasında değişebilir. Bir resmi bit eşleme olarak okuyup bit eşleme resmine dönüştürmeyi planlıyorsanız resimlerinizi res/raw/ klasörüne yerleştirin. Bu klasörde aapt aracı resimleri değiştirmez.
Aşağıdaki kod snippet'inde, çizilebilir bir kaynaktan oluşturulan resmi kullanan bir ImageView oluşturma ve bunu düzene ekleme işlemi gösterilmektedir:
Kotlin
private lateinit var constraintLayout: ConstraintLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Instantiate an ImageView and define its properties val i = ImageView(this).apply { setImageResource(R.drawable.my_image) contentDescription = resources.getString(R.string.my_image_desc) // set the ImageView bounds to match the Drawable's dimensions adjustViewBounds = true layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) } // Create a ConstraintLayout in which to add the ImageView constraintLayout = ConstraintLayout(this).apply { // Add the ImageView to the layout. addView(i) } // Set the layout as the content view. setContentView(constraintLayout) }
Java
ConstraintLayout constraintLayout; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create a ConstraintLayout in which to add the ImageView constraintLayout = new ConstraintLayout(this); // Instantiate an ImageView and define its properties ImageView i = new ImageView(this); i.setImageResource(R.drawable.my_image); i.setContentDescription(getResources().getString(R.string.my_image_desc)); // set the ImageView bounds to match the Drawable's dimensions i.setAdjustViewBounds(true); i.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); // Add the ImageView to the layout and set the layout as the content view. constraintLayout.addView(i); setContentView(constraintLayout); }
Diğer durumlarda, aşağıdaki örnekte gösterildiği gibi resim kaynağınızı Drawable nesnesi olarak işlemek isteyebilirsiniz:
Kotlin
val myImage: Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.my_image, null)
Java
Resources res = context.getResources(); Drawable myImage = ResourcesCompat.getDrawable(res, R.drawable.my_image, null);
Uyarı: Projenizdeki her benzersiz kaynak, kaç farklı nesne oluşturursanız oluşturun yalnızca tek bir durumu koruyabilir. Örneğin, aynı resim kaynağında iki Drawable nesnesi oluşturup bir nesnenin özelliğini (ör. alfa) değiştirirseniz bu değişiklik diğer nesneyi de etkiler. Bir resim kaynağının birden fazla örneğiyle uğraşırken Drawable nesnesini doğrudan dönüştürmek yerine tween
animasyonu yapmanız gerekir.
Aşağıdaki XML snippet'inde, XML düzenindeki bir ImageView öğesine drawable kaynak ekleme işlemi gösterilmektedir:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/my_image" android:contentDescription="@string/my_image_desc" />
Proje kaynaklarını kullanma hakkında daha fazla bilgi için Kaynaklar ve öğeler başlıklı makaleyi inceleyin.
Not: Çizilebilir öğelerinizin kaynağı olarak resim kaynaklarını kullanırken resimlerin çeşitli piksel yoğunlukları için uygun boyutta olduğundan emin olun. Resimler doğru değilse sığacak şekilde ölçeklendirilir. Bu durum, çizilebilir öğelerinizde yapaylık oluşmasına neden olabilir. Daha fazla bilgi için Farklı piksel yoğunluklarını destekleme başlıklı makaleyi inceleyin.
XML kaynaklarından çizilebilir öğeler oluşturma
Başlangıçta Drawable
kodunuz veya kullanıcı etkileşimi tarafından tanımlanan değişkenlere bağlı olmayan bir Drawable nesnesi oluşturmak istiyorsanız XML'de tanımlamak iyi bir seçenektir. Drawable öğenizin, kullanıcının uygulamanızla etkileşimi sırasında özelliklerini değiştirmesini bekliyor olsanız bile, nesne oluşturulduktan sonra özellikleri değiştirebileceğiniz için nesneyi XML'de tanımlamayı düşünmelisiniz.
XML'de Drawable tanımladıktan sonra dosyayı projenizin res/drawable/ dizinine kaydedin. Aşağıdaki örnekte, Drawable öğesinden devralan bir TransitionDrawable kaynağını tanımlayan XML gösterilmektedir:
<!-- res/drawable/expand_collapse.xml --> <transition xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/image_expand"/> <item android:drawable="@drawable/image_collapse"/> </transition>
Ardından, Resources#getDrawable()
çağırıp XML dosyanızın kaynak kimliğini ileterek nesneyi alın ve örnekleyin. Drawable alt sınıfı, inflate() yöntemini destekleyen herhangi bir XML'de tanımlanabilir ve uygulamanız tarafından örneklenebilir.
XML şişirmeyi destekleyen her çizilebilir sınıf, nesne özelliklerini tanımlamaya yardımcı olan belirli XML özelliklerini kullanır. Aşağıdaki kod, TransitionDrawable öğesini oluşturur
ve bunu ImageView nesnesinin içeriği olarak ayarlar:
Kotlin
val transition= ResourcesCompat.getDrawable( context.resources, R.drawable.expand_collapse, null ) as TransitionDrawable val image: ImageView = findViewById(R.id.toggle_image) image.setImageDrawable(transition) // Description of the initial state that the drawable represents. image.contentDescription = resources.getString(R.string.collapsed) // Then you can call the TransitionDrawable object's methods. transition.startTransition(1000) // After the transition is complete, change the image's content description // to reflect the new state.
Java
Resources res = context.getResources(); TransitionDrawable transition = (TransitionDrawable) ResourcesCompat.getDrawable(res, R.drawable.expand_collapse, null); ImageView image = (ImageView) findViewById(R.id.toggle_image); image.setImageDrawable(transition); // Description of the initial state that the drawable represents. image.setContentDescription(getResources().getString(R.string.collapsed)); // Then you can call the TransitionDrawable object's methods. transition.startTransition(1000); // After the transition is complete, change the image's content description // to reflect the new state.
Desteklenen XML özellikleri hakkında daha fazla bilgi için yukarıda listelenen sınıflara bakın.
Şekil çizilebilirleri
İki boyutlu bir grafiği dinamik olarak çizmek istediğinizde ShapeDrawable nesnesi iyi bir seçenek olabilir. ShapeDrawable nesnesinde temel şekilleri programatik olarak çizebilir ve uygulamanızın ihtiyaç duyduğu stilleri uygulayabilirsiniz.
ShapeDrawable, Drawable sınıfının alt sınıfıdır. Bu nedenle, Drawable beklenen her yerde ShapeDrawable kullanabilirsiniz. Örneğin, bir görünümün arka planını ayarlamak için ShapeDrawable nesnesini görünümün setBackgroundDrawable() yöntemine ileterek kullanabilirsiniz. Şeklinizi kendi özel görünümü olarak da çizebilir ve uygulamanızdaki bir düzene ekleyebilirsiniz.
ShapeDrawable kendi draw() yöntemine sahip olduğundan, aşağıdaki kod örneğinde gösterildiği gibi onDraw() etkinliği sırasında ShapeDrawable nesnesini çizen bir View alt sınıfı oluşturabilirsiniz:
Kotlin
class CustomDrawableView(context: Context) : View(context) { private val drawable: ShapeDrawable = run { val x = 10 val y = 10 val width = 300 val height = 50 contentDescription = context.resources.getString(R.string.my_view_desc) ShapeDrawable(OvalShape()).apply { // If the color isn't set, the shape uses black as the default. paint.color = 0xff74AC23.toInt() // If the bounds aren't set, the shape can't be drawn. setBounds(x, y, x + width, y + height) } } override fun onDraw(canvas: Canvas) { drawable.draw(canvas) } }
Java
public class CustomDrawableView extends View { private ShapeDrawable drawable; public CustomDrawableView(Context context) { super(context); int x = 10; int y = 10; int width = 300; int height = 50; setContentDescription(context.getResources().getString( R.string.my_view_desc)); drawable = new ShapeDrawable(new OvalShape()); // If the color isn't set, the shape uses black as the default. drawable.getPaint().setColor(0xff74AC23); // If the bounds aren't set, the shape can't be drawn. drawable.setBounds(x, y, x + width, y + height); } protected void onDraw(Canvas canvas) { drawable.draw(canvas); } }
Yukarıdaki kod örneğinde CustomDrawableView sınıfını diğer özel görünümleri kullandığınız gibi kullanabilirsiniz. Örneğin, aşağıdaki örnekte gösterildiği gibi, uygulamanızdaki bir etkinliğe programatik olarak ekleyebilirsiniz:
Kotlin
private lateinit var customDrawableView: CustomDrawableView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) customDrawableView = CustomDrawableView(this) setContentView(customDrawableView) }
Java
CustomDrawableView customDrawableView; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); customDrawableView = new CustomDrawableView(this); setContentView(customDrawableView); }
Bunun yerine XML düzeninde özel görünümü kullanmak istiyorsanız CustomDrawableView sınıfı, sınıf XML'den büyütüldüğünde çağrılan View(Context, AttributeSet) oluşturucusunu geçersiz kılmalıdır. Aşağıdaki örnekte, XML düzeninde CustomDrawableView öğesinin nasıl bildirileceği gösterilmektedir:
<com.example.shapedrawable.CustomDrawableView android:layout_width="fill_parent" android:layout_height="wrap_content" />
ShapeDrawable sınıfı, android.graphics.drawable paketindeki diğer birçok çizilebilir tür gibi, ortak yöntemleri kullanarak nesnenin çeşitli özelliklerini tanımlamanıza olanak tanır. Ayarlamak isteyebileceğiniz bazı örnek özellikler arasında alfa şeffaflığı, renk filtresi, titreşim, opaklık ve renk bulunur.
XML kaynaklarını kullanarak temel çizilebilir şekiller de tanımlayabilirsiniz. Daha fazla bilgi için Drawable kaynak türleri bölümündeki Şekil drawable başlıklı makaleyi inceleyin.
NinePatch çizilebilir öğeleri
NinePatchDrawable grafiği, görünümün arka planı olarak kullanabileceğiniz, genişletilebilir bir bit eşlem resmidir. Android, görünümün içeriğine uyacak şekilde grafiği otomatik olarak yeniden boyutlandırır. NinePatch resimlerinin kullanımına örnek olarak, standart Android düğmelerinde kullanılan arka plan verilebilir. Düğmeler, çeşitli uzunluklardaki dizeleri barındıracak şekilde genişletilmelidir. NinePatch grafiği, 1 piksellik ek bir kenarlık içeren standart bir PNG resmidir.
Bu dosya, projenizin res/drawable/ dizininde 9.png uzantısıyla kaydedilmelidir.
Resmin uzatılabilir ve statik alanlarını tanımlamak için kenarlığı kullanın. Sınırın sol ve üst kısmına 1 piksel genişliğinde bir veya daha fazla siyah çizgi çizerek esnetilebilir bir bölümü belirtirsiniz (diğer sınır pikselleri tamamen şeffaf veya beyaz olmalıdır). İstediğiniz kadar esnetilebilir bölüm ekleyebilirsiniz. Esnetilebilir bölümlerin göreli boyutu aynı kalır. Bu nedenle, en büyük bölüm her zaman en büyük bölüm olmaya devam eder.
Ayrıca sağa ve alta birer çizgi çizerek resmin isteğe bağlı bir çizilebilir bölümünü (aslında dolgu çizgileri) de tanımlayabilirsiniz. Bir View nesnesi, NinePatch grafiğini arka planı olarak ayarlayıp görünümün metnini belirtirse tüm metin yalnızca sağ ve alt çizgilerle (varsa) belirlenen alanı kaplayacak şekilde kendini genişletir.
Dolgu çizgileri dahil edilmezse Android, bu çizilebilir alanı tanımlamak için sol ve üst çizgileri kullanır.
Çizgiler arasındaki farkı netleştirmek için sol ve üst çizgilerin, görüntüyü uzatmak amacıyla hangi görüntü piksellerinin kopyalanmasına izin verildiğini tanımladığını belirtmek isteriz. Alt ve sağ çizgiler, görünümün içeriğinin resimde kaplamasına izin verilen göreli alanı tanımlar.
Şekil 1'de, bir düğmeyi tanımlamak için kullanılan NinePatch grafiği örneği gösterilmektedir:
Şekil 1: Düğmeyi tanımlayan NinePatch grafik örneği
Bu NinePatch grafiği, sol ve üst çizgilerle gerilebilir bir alanı, alt ve sağ çizgilerle ise çizilebilir alanı tanımlar. Üstteki resimde, noktalı gri çizgiler, resmi uzatmak için kopyalanan bölgeleri gösterir. Alttaki resimde yer alan pembe dikdörtgen, görünümdeki içeriklere izin verilen bölgeyi gösterir. İçerikler bu bölgeye sığmıyorsa sığmaları için resim gerilir.
9 bölümlü çizim aracı, WYSIWYG grafik düzenleyicisi kullanarak NinePatch resimlerinizi oluşturmak için son derece kullanışlı bir yöntem sunar. Hatta esnetilebilir alan için tanımladığınız bölge, piksel kopyalama nedeniyle çizim artefaktları oluşturma riski taşıyorsa uyarı verir.
Aşağıdaki örnek düzen XML'sinde, birkaç düğmeye NinePatch grafiğinin nasıl ekleneceği gösterilmektedir. NinePatch resmi res/drawable/my_button_background.9.png konumuna kaydedilir.
<Button android:id="@+id/tiny" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerInParent="true" android:text="Tiny" android:textSize="8sp" android:background="@drawable/my_button_background"/> <Button android:id="@+id/big" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerInParent="true" android:text="Biiiiiiig text!" android:textSize="30sp" android:background="@drawable/my_button_background"/>
layout_width ve layout_height özelliklerinin, düğmenin metnin etrafına düzgün şekilde sığması için wrap_content olarak ayarlandığını unutmayın.
Şekil 2'de, yukarıda gösterilen XML ve NinePatch resminden oluşturulan iki düğme gösterilmektedir. Düğmenin genişliğinin ve yüksekliğinin metne göre nasıl değiştiğine ve arka plan resminin bunu karşılamak için nasıl uzadığına dikkat edin.
Şekil 2: XML kaynağı ve NinePatch grafiği kullanılarak oluşturulan düğmeler
Özel çizilebilir öğeler
Özel çizimler oluşturmak istediğinizde Drawable sınıfını (veya alt sınıflarından herhangi birini) genişleterek bunu yapabilirsiniz.
Uygulanacak en önemli yöntem draw(Canvas)
çünkü bu, çizim talimatlarınızı sağlamak için kullanmanız gereken Canvas nesnesini sağlar.
Aşağıdaki kodda, daire çizen basit bir Drawable alt sınıfı gösterilmektedir:
Kotlin
class MyDrawable : Drawable() { private val redPaint: Paint = Paint().apply { setARGB(255, 255, 0, 0) } override fun draw(canvas: Canvas) { // Get the drawable's bounds val width: Int = bounds.width() val height: Int = bounds.height() val radius: Float = Math.min(width, height).toFloat() / 2f // Draw a red circle in the center canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, redPaint) } override fun setAlpha(alpha: Int) { // This method is required } override fun setColorFilter(colorFilter: ColorFilter?) { // This method is required } override fun getOpacity(): Int = // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE PixelFormat.OPAQUE }
Java
public class MyDrawable extends Drawable { private final Paint redPaint; public MyDrawable() { // Set up color and text size redPaint = new Paint(); redPaint.setARGB(255, 255, 0, 0); } @Override public void draw(Canvas canvas) { // Get the drawable's bounds int width = getBounds().width(); int height = getBounds().height(); float radius = Math.min(width, height) / 2; // Draw a red circle in the center canvas.drawCircle(width/2, height/2, radius, redPaint); } @Override public void setAlpha(int alpha) { // This method is required } @Override public void setColorFilter(ColorFilter colorFilter) { // This method is required } @Override public int getOpacity() { // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE return PixelFormat.OPAQUE; } }
Ardından, çizilebilir öğenizi istediğiniz yere ekleyebilirsiniz. Örneğin, burada gösterildiği gibi bir ImageView öğesine ekleyebilirsiniz:
Kotlin
val myDrawing = MyDrawable() val image: ImageView = findViewById(R.id.imageView) image.setImageDrawable(myDrawing) image.contentDescription = resources.getString(R.string.my_image_desc)
Java
MyDrawable mydrawing = new MyDrawable(); ImageView image = findViewById(R.id.imageView); image.setImageDrawable(mydrawing); image.setContentDescription(getResources().getString(R.string.my_image_desc));
Android 7.0 (API düzeyi 24) ve sonraki sürümlerde, özel çizilebilir öğenizin örneklerini XML ile aşağıdaki şekillerde de tanımlayabilirsiniz:
- Tam nitelikli sınıf adını XML öğe adı olarak kullanma. Bu yaklaşım için özel çizilebilir sınıf, herkese açık üst düzey bir sınıf olmalıdır:
<com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android" android:color="#ffff0000" />
- XML etiketi adı olarak
drawableöğesini kullanma ve sınıf özelliğinden tam nitelikli sınıf adını belirtme. Bu yaklaşım hem herkese açık üst düzey sınıflar hem de herkese açık statik iç sınıflar için kullanılabilir:<drawable xmlns:android="http://schemas.android.com/apk/res/android" class="com.myapp.MyTopLevelClass$MyDrawable" android:color="#ffff0000" />
Çizilebilir öğelere renk tonu ekleme
Android 5.0 (API düzeyi 21) ve sonraki sürümlerde, alfa maskeleri olarak tanımlanan bit eşlemleri ve dokuz yamaları renklendirebilirsiniz. Bunları, renk kaynaklarına (ör. ?android:attr/colorPrimary) dönüşen renk kaynakları veya tema özellikleriyle renklendirebilirsiniz. Genellikle bu öğeleri yalnızca bir kez oluşturur ve temanızla eşleşecek şekilde otomatik olarak renklendirirsiniz.
BitmapDrawable, NinePatchDrawable veya VectorDrawable nesnelerine setTint() yöntemiyle renk tonu uygulayabilirsiniz. Ayrıca, android:tint ve android:tintMode özellikleriyle düzenlerinizde renk tonunu ve modunu da ayarlayabilirsiniz.
Bir resimdeki belirgin renkleri ayıklama
Android Destek Kitaplığı, bir resimden belirgin renkleri almanızı sağlayan Palette sınıfını içerir.
Çizilebilir öğelerinizi Bitmap olarak yükleyip renklerine erişmek için Palette öğesine iletebilirsiniz.
Daha fazla bilgi için Palet API'si ile renk seçme başlıklı makaleyi inceleyin.