Çekilebilir öğelere genel bakış

Oluşturma yöntemini deneyin
Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir. Compose'da grafiklerin nasıl görüntüleneceğini öğrenin.

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, çizilebilecek bir şeye ilişkin genel bir soyutlamadır. Çeşitli alt sınıflar, belirli görüntü senaryolarına yardımcı olur. Bunları, benzersiz şekillerde davranan kendi çekilebilir nesnelerinizi tanımlamak için genişletebilirsiniz.

Sınıf kurucularını kullanmanın yanı sıra Drawable öğesini tanımlamanın ve örneklendirmenin iki yolu vardır:

  • Projenizde kayıtlı bir resim kaynağını (bit eşlem dosyası) şişirir.
  • Çekilebilir özellikleri tanımlayan bir XML kaynağını şişirin.

Not: Bunun yerine, bir dizi nokta, çizgi ve eğriden oluşan bir resmi ve ilişkili renk bilgilerini tanımlayan bir vektör çekilebilir özelliğini kullanmayı tercih edebilirsiniz. Bu şekilde vektör çekilebilirlerinin, kaliteden ödün vermeden farklı boyutlar için ölçeklendirilmesine olanak sağlanır. Daha fazla bilgi için Vektör çizimlerine genel bakış konusuna göz atın.

Kaynak resimlerinden çekilebilir çizimler oluşturma

Proje kaynaklarınızdaki bir görüntü dosyasına referans vererek uygulamanıza grafik ekleyebilirsiniz. Desteklenen dosya türleri PNG (tercih edilir), JPG (kabul edilebilir) ve GIF'tir (önerilmez). Uygulama simgeleri, logolar ve oyunlarda kullanılanlar gibi diğer grafikler bu tekniğe uygundur.

Bir resim kaynağı kullanmak için dosyanızı, projenizin res/drawable/ dizinine ekleyin. Projenize girdikten sonra, kodunuzdaki veya XML düzeninizdeki resim kaynağına başvurabilirsiniz. Her iki durumda da, dosya türü uzantısı olmayan dosya adı olan bir kaynak kimliği kullanılır. Örneğin, my_image.png için my_image olarak başvuruda bulunun.

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 yöntemiyle otomatik olarak optimize edilebilir. Örneğin, 256'dan fazla renk gerektirmeyen gerçek renkli bir PNG, renk paletine sahip 8 bit bir PNG'ye dönüştürülebilir. Bu, eşit kalitede ancak daha az bellek gerektiren bir resimle sonuçlanır. Sonuç olarak, bu dizine yerleştirilen görüntü ikili programları derleme sırasında değişebilir. Bir görüntüyü bit eşlem olarak okumak için bit eşlem olarak okumayı planlıyorsanız resimlerinizi res/raw/ klasörüne yerleştirin. aapt aracı, bunları değiştirmez.

Aşağıdaki kod snippet'i, çekilebilir bir kaynaktan oluşturulan resmi kullanan ve bunu düzene ekleyen bir ImageView öğesinin nasıl oluşturulacağını gösterir:

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, resim kaynağınızı aşağıdaki örnekte gösterildiği gibi bir Drawable nesnesi olarak kullanmak 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 sunduğunuzdan bağımsız olarak yalnızca bir durumu koruyabilir. Örneğin, aynı resim kaynağından iki Drawable nesnesini örneklendirir ve bir nesnenin özelliğini (alfa gibi) değiştirirseniz bu değişiklik diğerini de etkiler. Bir görüntü kaynağının birden çok örneğiyle çalışırken, Drawable nesnesini doğrudan dönüştürmek yerine bir ara animasyonu gerçekleştirmeniz gerekir.

Aşağıdaki XML snippet'i, XML düzeninde bir ImageView öğesine çekilebilir kaynağın nasıl ekleneceğini gösterir:

<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 bölümüne bakın.

Not: Çekilebilir malzemelerinizin 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 büyütülür. Bu da, çizimlerinizde oluşumlara neden olabilir. Daha fazla bilgi için Farklı piksel yoğunluklarını destekleme bölümünü okuyun.

XML kaynaklarından çekilebilir çizimler oluşturma

Başlangıçta kodunuz veya kullanıcı etkileşiminiz tarafından tanımlanan değişkenlere bağlı olmayan, oluşturmak istediğiniz bir Drawable nesnesi varsa Drawable öğesini 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 bekleseniz bile, nesne örneklendikten sonra özelliklerini değiştirebileceğiniz için nesneyi XML'de tanımlamayı düşünmelisiniz.

Drawable öğenizi XML'de tanımladıktan sonra, dosyayı projenizin res/drawable/ dizinine kaydedin. Aşağıdaki örnek, Drawable kaynağından devralan bir TransitionDrawable kaynağını tanımlayan XML'i göstermektedir:

<!-- 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() yöntemini çağırıp XML dosyanızın kaynak kimliğini ileterek nesneyi alın ve örneklendirin. inflate() yöntemini destekleyen tüm Drawable alt sınıfları XML'de tanımlanabilir ve uygulamanız tarafından örneklenebilir.

XML şişirmeyi destekleyen her çekilebilir sınıf, nesne özelliklerinin tanımlanmasına yardımcı olan belirli XML özelliklerini kullanır. Aşağıdaki kod TransitionDrawable öğesini somutlaştırır ve bir 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 çekilebilir öğeleri

Dinamik olarak iki boyutlu bir grafik çizmek istediğinizde ShapeDrawable nesnesi iyi bir seçenek olabilir. Programatik olarak bir ShapeDrawable nesnesine temel şekiller çizebilir ve uygulamanızın ihtiyaç duyduğu stilleri uygulayabilirsiniz.

ShapeDrawable, Drawable sınıfının bir alt sınıfıdır. Bu nedenle, Drawable olması beklenen her yerde ShapeDrawable kullanabilirsiniz. Örneğin, bir görünümün setBackgroundDrawable() yöntemine ileterek görünümün arka planını ayarlamak için bir ShapeDrawable nesnesi kullanabilirsiniz. Ayrıca şeklinizi kendi özel görünümü olarak çizleyebilir 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ümlerde olduğu gibi kullanabilirsiniz. Örneğin, bunu aşağıdaki örnekte gösterildiği gibi programatik olarak uygulamanızdaki bir etkinliğe 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 özel görünümü XML düzeninde kullanmak isterseniz CustomDrawableView sınıfı, sınıf XML'den şişirildiğinde çağrılan View(Context, AttributeSet) oluşturucuyu 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 çekilebilir tür gibi, herkese açık yöntemler kullanarak nesnenin çeşitli özelliklerini tanımlamanıza olanak tanır. Ayarlamak isteyebileceğiniz bazı örnek özellikler arasında alfa şeffaflığı, renk filtresi, parlaklık, opaklık ve renk yer alır.

XML kaynaklarını kullanarak temel çekilebilir şekilleri de tanımlayabilirsiniz. Daha fazla bilgi için Çekilebilir kaynak türleri bölümündeki Şekil çizimi bölümüne bakın.

NinePatch çekmeceleri

NinePatchDrawable grafiği, bir görünümün arka planı olarak kullanabileceğiniz uzatılabilir bir bit eşlem resmidir. Android, görünümün içeriğine uygun olması için grafiği otomatik olarak yeniden boyutlandırır. NinePatch resminin kullanımına örnek olarak, standart Android düğmeleri tarafından kullanılan arka plan verilebilir. Düğmeler, çeşitli uzunluklardaki dizeleri kapsayacak şekilde genişletilmelidir. NinePatch grafiği, ekstra 1 piksel kenarlık içeren standart bir PNG resmidir. Söz konusu değer, projenizin res/drawable/ dizinine 9.png uzantısıyla kaydedilmelidir.

Resmin uzatılabilir ve statik alanlarını tanımlamak için kenarlığı kullanın. Kenarlığın sol ve üst kısmına bir (veya daha fazla) 1 piksel genişliğinde siyah çizgi çizerek uzatılabilir bir bölüm belirtirsiniz (diğer kenarlık pikselleri tamamen şeffaf veya beyaz olmalıdır). İstediğiniz sayıda uzatılabilir bölümünüz olabilir. Uzatılabilir bölümlerin göreli boyutu aynı kalır, böylece en büyük bölüm her zaman en büyük olmaya devam eder.

Ayrıca sağ tarafa bir çizgi ve alta bir çizgi çizerek resmin isteğe bağlı çekilebilir bir bölümünü (doldurma çizgileri etkili bir şekilde) tanımlayabilirsiniz. Bir View nesnesi, NinePatch grafiğini arka plan olarak ayarlar ve daha sonra görünümün metnini belirtirse, tüm metin yalnızca sağ ve alt satırlarla (varsa) belirtilen alanı kaplayacak şekilde kendini uzatır. Dolgu çizgileri dahil edilmezse Android bu çekilebilir alanı tanımlamak için sol ve üst çizgileri kullanır.

Çizgiler arasındaki farkı netleştirmek amacıyla, sol ve üst çizgiler, resmi genişletmek için resmin hangi piksellerinin çoğaltılmasına izin verileceğini tanımlar. Alt ve sağ çizgiler, resim içinde, görünüm içeriğinin doldurmasına izin verilen göreli alanı tanımlar.

Şekil 1'de, bir düğmeyi tanımlamak için kullanılan bir NinePatch grafiği örneği gösterilmektedir:

Uzatılabilir alanın ve dolgu kutusunun resmi

Şekil 1: Bir düğmeyi tanımlayan NinePatch grafiği örneği

Bu NinePatch grafiği, sol ve üst çizgileri olan uzatılabilir bir alanı ve alt ve sağ çizgileri olan çekilebilir alanı tanımlar. Üstteki resimde bulunan kesik gri çizgiler, resmi esnetmek için görüntünün çoğaltılan bölgelerini belirtir. Alt resimdeki pembe dikdörtgen, görünümün içeriklerine izin verilen bölgeyi belirtir. İçerikler bu bölgeye sığmazsa resim genişletilerek bunların sığması sağlanır.

Draw 9-patch aracı, WYSIWYG grafik düzenleyici kullanarak NinePatch resimlerinizi oluşturmanız için son derece pratik bir yol sunar. Hatta, uzatılabilir alan için tanımladığınız bölge, piksel çoğaltma nedeniyle çizim kusurları oluşturma riskiyle karşı karşıya kalırsa uyarı verir.

Aşağıdaki örnek düzen XML'inde, birkaç düğmeye NinePatch grafiğinin nasıl ekleneceği gösterilmektedir. NinePatch resmi res/drawable/my_button_background.9.png klasörüne 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"/>

Düğmenin metnin etrafına düzgün bir şekilde sığması için layout_width ve layout_height özelliklerinin 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 buna göre genişlediğine dikkat edin.

Küçük ve normal boyutlu düğmelerin

Şekil 2: XML kaynağı ve NinePatch grafiği kullanılarak oluşturulan düğmeler

Özel çekilebilir cihazlar

Drawable sınıfını (veya alt sınıflarından herhangi birini) genişleterek özel çizimler oluşturabilirsiniz.

Uygulanacak en önemli yöntem draw(Canvas) yöntemidir. Çünkü bu yöntem, ç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, çekilebilir dosyanızı burada gösterildiği gibi bir ImageView ekleme gibi istediğiniz yere 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, XML ile özel çiziminizin örneklerini aşağıdaki yöntemlerle de tanımlayabilirsiniz:

  • XML öğesi adı olarak tam nitelikli sınıf adını kullanma. Bu yaklaşımda özel çekilebilir sınıf sınıfının herkese açık üst düzey sınıf olması gerekir:
    <com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="#ffff0000" />
    
  • XML etiketi adı olarak drawable kullanma ve class ö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" />
    

Çekilebilir alanlara 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 yamayı renklendirebilirsiniz. Renk kaynaklarını çözen renk kaynakları veya tema özellikleriyle renklendirme yapabilirsiniz (örneğin, ?android:attr/colorPrimary). Genellikle bu öğeleri yalnızca bir kez oluşturur ve temanızla eşleşecek şekilde otomatik olarak renklendirirsiniz.

setTint() yöntemiyle BitmapDrawable, NinePatchDrawable veya VectorDrawable nesnelerine tonlama uygulayabilirsiniz. android:tint ve android:tintMode özelliklerini kullanarak düzenlerinizde ton rengini ve modunu da ayarlayabilirsiniz.

Görselden belirgin renkleri çıkarabilirsiniz

Android Destek Kitaplığı, bir görselden belirgin renkleri ayıklamanıza olanak tanıyan Palette sınıfını içerir. Çekilebilir öğelerinizi Bitmap olarak yükleyip renklerine erişmek için Palette ile aktarabilirsiniz. Daha fazla bilgi için Palet API'si ile renk seçme bölümünü okuyun.