Çekilebilir öğelere genel bakış

Oluşturma yöntemini deneyin
Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir. Oluşturma aracında grafikleri nasıl görüntüleyeceğinizi öğ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 şey için 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 bir Drawable öğesini tanımlamanın ve somutlaştırmanın iki yolu vardır:

  • Projenizde kayıtlı bir görüntü 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, vektör çekilebilirlerinin kaliteden ödün vermeden farklı boyutlar için ölçeklendirilmesine olanak tanır. Daha fazla bilgi için Vektör çizimlerine genel bakış bölümünü inceleyin.

Kaynak resimlerden çekilebilir metinler 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, kodunuzdan veya XML düzeninizden görüntü kaynağına başvurabilirsiniz. Her iki yöntemde de, dosya türü uzantısı olmayan dosya adı olan bir kaynak kimliği kullanılır. Örneğin, my_image.png öğesine my_image olarak bakı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 kullanılarak otomatik olarak optimize edilebilir. Örneğin, 256'dan fazla renk gerektirmeyen gerçek renkli bir PNG, renk paleti içeren 8 bit bir PNG'ye dönüştürülebilir. Böylece, eşit kalitede ancak daha az bellek gerektiren bir resim elde edilir. Sonuç olarak, bu dizine yerleştirilen görüntü ikili programları derleme zamanında değişebilir. Bir görüntüyü bit eşlem olarak dönüştürmek için bit akışı olarak okumayı planlıyorsanız, resimlerinizi aapt aracının değiştirmeyeceği res/raw/ klasörüne yerleştirin.

Aşağıdaki kod snippet'i, çekilebilir bir kaynaktan oluşturulmuş bir görüntüyü 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 başlatırsanız sunun 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 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 animasyon uygulamanız 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 başlıklı makaleye 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 ölçeklendirilirler. Bu da, çekilebilirlerinizde öğelere neden olabilir. Daha fazla bilgi için Farklı piksel yoğunluklarını destekleme bölümünü okuyun.

XML kaynaklarından çekilebilir öğeler oluşturma

Başlangıçta kodunuz veya kullanıcı etkileşiminiz tarafından tanımlanan değişkenlere bağlı olmayan bir Drawable nesnesi oluşturmak istiyorsanız XML'de Drawable öğesini tanımlamak iyi bir seçenektir. Kullanıcının uygulamanızla etkileşimi sırasında Drawable ürününüzün özelliklerini değiştirmesini bekleseniz bile, nesne örneklendikten sonra özelliklerini değiştirebileceğiniz için nesneyi XML biçiminde tanımlamayı düşünmelisiniz.

Drawable öğenizi XML'de tanımladıktan sonra, dosyayı projenizin res/drawable/ dizinine kaydedin. Aşağıdaki örnekte, Drawable kaynağından 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() 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 olarak tanımlanabilir ve uygulamanız tarafından örneklenebilir.

XML şişirmeyi destekleyen her çekilebilir sınıf, nesne özelliklerini tanımlamaya 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.

Çekilebilir şekiller

İki boyutlu bir grafiği dinamik olarak çizmek istediğinizde ShapeDrawable nesnesi iyi bir seçenek olabilir. Programatik olarak bir ShapeDrawable nesnesi üzerinde 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 ShapeDrawable nesnesini görünümün setBackgroundDrawable() yöntemine geçirerek bir görünümün arka planını ayarlamak için kullanabilirsiniz. Şeklinizi kendi özel görünümü olarak ç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, diğer tüm özel görünümlerde olduğu gibi CustomDrawableView sınıfını kullanabilirsiniz. Örneğin, bunu 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 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 belirtileceğ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 çekilebilir bölümüne bakın.

NinePatch çekilebilir birimleri

NinePatchDrawable grafiği, 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 uyması 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üğmelerin çeşitli uzunluklardaki dizelere uyum sağlamak için genişletilmesi gerekir. NinePatch grafiği, ekstra 1 piksellik bir kenarlık içeren standart bir PNG resmidir. 9.png uzantısıyla birlikte projenizin res/drawable/ dizinine kaydedilmelidir.

Resmin uzatılabilir ve statik alanlarını tanımlamak için kenarlığı kullanın. Kenarlığın sol ve üst kısmına 1 piksel genişliğinde bir (veya daha fazla) siyah çizgi çizerek uzatılabilir bir bölümü belirtirsiniz (diğer kenarlık pikselleri tamamen şeffaf veya beyaz olmalıdır). İstediğiniz kadar 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ğa ve alta bir çizgi çizerek resmin isteğe bağlı çekilebilir bir bölümünü (etkili bir şekilde dolgu çizgileri) tanımlayabilirsiniz. Bir View nesnesi, NinePatch grafiğini arka plan olarak ayarlar ve daha sonra, görünümün metnini belirtirse metnin tamamı, yalnızca sağ ve alt çizgiler (varsa) tarafından belirtilen alanı dolduracak şekilde kendisini uzatır. Dolgu çizgileri eklenmezse 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 uzatmak için resmin hangi piksellerinin kopyalanmasına izin verileceğini tanımlar. Alt ve sağ çizgiler, resim içinde görünüm içeriğinin kapladığı 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 çizgilerle uzatılabilir bir alanı, alt ve sağ çizgilerle çekilebilir alanı tanımlar. Üstteki resimde bulunan noktalı gri çizgiler, görüntünün esnetmek için kopyalanan bölgelerini tanımlar. Alttaki resimdeki pembe dikdörtgen, görünüm içeriğine 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ı, bir WYSIWYG grafik düzenleyici kullanarak NinePatch resimlerinizi oluşturmak için son derece kullanışlı bir yol sunar. Hatta, uzatılabilir alan için tanımladığınız bölge, piksel çoğaltma nedeniyle çizim yapıları oluşturma riskiyle karşı karşıyaysa 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 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"/>

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üğme genişliğinin ve yüksekliğinin metne göre nasıl değiştiğine ve arka plan resminin uygun şekilde genişlediğine dikkat edin.

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

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

Özel çekilebilir kaynaklar

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

Uygulanacak en önemli yöntem, çizim talimatlarınızı sağlamak için kullanmanız gereken Canvas nesnesini sağladığından draw(Canvas) yöntemidir.

Aşağıdaki kod, daire çizen basit bir Drawable alt sınıfını göstermektedir:

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;
    }
}

Daha sonra, çekilebilir dosyanızı burada gösterildiği gibi bir ImageView öğesine 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 çekilebilir dosyanızın örneklerini aşağıdaki yöntemlerle de tanımlayabilirsiniz:

  • XML öğe adı olarak tam nitelikli sınıf adını kullanma. Bu yaklaşımda özel çekilebilir 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 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 öğelere ton 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ıyla uyumlu hale getiren renk kaynakları veya tema özellikleriyle Tonlama uygulayabilirsiniz (ö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. Ayrıca, android:tint ve android:tintMode özelliklerini kullanarak düzenlerinizde tonlama rengini ve modunu da ayarlayabilirsiniz.

Görseldeki belirgin renkleri ayıklayın

Android Destek Kitaplığı, resimlerden belirgin renkleri çıkarabilmenizi sağlayan Palette sınıfını içerir. Çekilebilir öğelerinizi Bitmap olarak yükleyip renklerine erişmesi için Palette adlı iş ortağına iletebilirsiniz. Daha fazla bilgi için Palet API'si ile renk seçme bölümünü okuyun.