Çok gradyanlı şekiller


177

Aşağıdaki resme benzeyen bir şekil oluşturmak istiyorum:

alternatif metin

Renk 1'den renk 2'ye üst yarı degradelere dikkat edin, ancak renk 3'ten renk 4'e degradelerin bir alt yarısı vardır. iki yarım ve 2 farklı gradyan ile 1 şekil yapmak.

Herhangi bir fikir?


Yanıtlar:


383

Bunu XML'de yapabileceğinizi düşünmüyorum (en azından Android'de değil), ancak burada yayınlanan , çok yardımcı olacak gibi görünen iyi bir çözüm buldum !

ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
    @Override
    public Shader resize(int width, int height) {
        LinearGradient lg = new LinearGradient(0, 0, width, height,
            new int[]{Color.GREEN, Color.GREEN, Color.WHITE, Color.WHITE},
            new float[]{0,0.5f,.55f,1}, Shader.TileMode.REPEAT);
        return lg;
    }
};

PaintDrawable p=new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);

Temel olarak, int dizisi birden çok renk durağı seçmenize izin verir ve aşağıdaki kayan dizi, bu durakların nereye yerleştirileceğini tanımlar (0'dan 1'e). Daha sonra, belirtildiği gibi, bunu standart bir Çekilebilir olarak kullanabilirsiniz.

Düzenleme: Senaryoda bunu nasıl kullanabilirsiniz. XML'de şu şekilde tanımlanmış bir Button'ınız olduğunu varsayalım:

<Button
    android:id="@+id/thebutton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Press Me!"
    />

Daha sonra onCreate () yönteminize böyle bir şey koyardınız:

Button theButton = (Button)findViewById(R.id.thebutton);
ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
    @Override
    public Shader resize(int width, int height) {
        LinearGradient lg = new LinearGradient(0, 0, 0, theButton.getHeight(),
            new int[] { 
                Color.LIGHT_GREEN, 
                Color.WHITE, 
                Color.MID_GREEN, 
                Color.DARK_GREEN }, //substitute the correct colors for these
            new float[] {
                0, 0.45f, 0.55f, 1 },
            Shader.TileMode.REPEAT);
         return lg;
    }
};
PaintDrawable p = new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);
theButton.setBackground((Drawable)p);

Bunu şu anda test edemiyorum, bu kafamdan gelen kod, ancak temel olarak sadece değiştirin veya ihtiyacınız olan renkler için duraklar ekleyin. Temel olarak, örneğimde, açık yeşil ile başlayacaksınız, merkezden biraz önce beyaza doğru solmaya (sert bir geçiş yerine solmaya vermek),% 45 ile% 55 arasında beyazdan orta yeşile solmaya, sonra solmaya orta yeşilden koyu yeşile% 55'ten sonuna kadar. Bu tam olarak şeklinize benzemeyebilir (Şu anda bu renkleri test etmenin bir yolu yok), ancak örneğinizi çoğaltmak için bunu değiştirebilirsiniz.

Düzenle: Ayrıca, 0, 0, 0, theButton.getHeight()degradenin x0, y0, x1, y1 koordinatlarını ifade eder. Temel olarak, x = 0 (sol taraf), y = 0 (üst) ile başlar ve x = 0'a uzanır (dikey bir degrade istiyoruz, bu nedenle soldan sağa açı gerekli değildir), y = yükseklik düğmesinin. Böylece degrade düğmenin üstünden düğmenin altına 90 derecelik bir açıyla gider.

Edit: Tamam, bu yüzden işe yarar bir fikrim daha var, haha. Şu anda XML'de çalışıyor, ancak Java'daki şekiller için de yapılabilir. Bu biraz karmaşık ve tek bir şekle sadeleştirmenin bir yolu olduğunu hayal ediyorum, ama şimdilik bu var:

green_horizontal_gradient.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <corners
        android:radius="3dp"
        />
    <gradient
        android:angle="0"
        android:startColor="#FF63a34a"
        android:endColor="#FF477b36"
        android:type="linear"
        />    
</shape>

half_overlay.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <solid
        android:color="#40000000"
        />
</shape>

layer_list.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item
        android:drawable="@drawable/green_horizontal_gradient"
        android:id="@+id/green_gradient"
        />
    <item
        android:drawable="@drawable/half_overlay"
        android:id="@+id/half_overlay"
        android:top="50dp"
        />
</layer-list>

test.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    >
    <TextView
        android:id="@+id/image_test"
        android:background="@drawable/layer_list"
        android:layout_width="fill_parent"
        android:layout_height="100dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:gravity="center"
        android:text="Layer List Drawable!"
        android:textColor="@android:color/white"
        android:textStyle="bold"
        android:textSize="26sp"     
        />
</RelativeLayout>

Tamam, temelde XML'de yatay yeşil degrade için, üst alanın sol yeşil renginden sağ yeşil renge doğru 0 derecelik bir açıya ayarlanmış bir şekil gradyanı oluşturdum. Sonra, yarı şeffaf gri bir şekil dikdörtgeni yaptım. Bu ekstra dosyayı ortadan kaldırarak, katman listesi XML içine satır içine olabilir eminim, ama nasıl emin değilim. Ama tamam, o zaman hacky kısmı tür layer_list XML dosyasında geliyor. Yeşil degradeyi alt katman olarak koydum, sonra yarım katmanı ikinci katman olarak koydum, üstten 50dp ile dengeledim. Açıkçası, bu sayının her zaman görüntüleme boyutunuzun yarısı olmasına ve sabit bir 50dp olmasını istemezsiniz. Yine de yüzdeleri kullanabileceğinizi sanmıyorum. Oradan, layer_list.xml dosyasını arka planım olarak kullanarak test.xml düzenime bir TextView ekledim.

alternatif metin

Tada!

Bir düzenleme daha : Şekilleri öğeler olarak çizilebilen katman listesine gömebildiğinizi fark ettim, yani artık 3 ayrı XML dosyasına ihtiyacınız yok! Bunları bir araya getirerek aynı sonucu elde edebilirsiniz:

layer_list.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item>
        <shape
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="rectangle"
            >
            <corners
                android:radius="3dp"
                />
            <gradient
                android:angle="0"
                android:startColor="#FF63a34a"
                android:endColor="#FF477b36"
                android:type="linear"
                />    
        </shape>
    </item>
    <item
        android:top="50dp" 
        >
        <shape
            android:shape="rectangle"
            >
            <solid
                android:color="#40000000"
                />
        </shape>            
    </item>
</layer-list>

Bu şekilde istediğiniz kadar öğe katlayabilirsiniz! Oynamaya çalışabilir ve Java aracılığıyla daha çok yönlü bir sonuç alıp alamayacağımı görebilirim.

Sanırım bu son düzenleme ... : Tamam, bu yüzden Java gibi konumlandırmayı kesinlikle düzeltebilirsiniz:

    TextView tv = (TextView)findViewById(R.id.image_test);
    LayerDrawable ld = (LayerDrawable)tv.getBackground();
    int topInset = tv.getHeight() / 2 ; //does not work!
    ld.setLayerInset(1, 0, topInset, 0, 0);
    tv.setBackgroundDrawable(ld);

Ancak! Bu, TextView çizilene kadar ölçemediğiniz için başka bir can sıkıcı soruna yol açar. Bunu nasıl başarabileceğinizden henüz emin değilim ... ancak topInset için manuel olarak bir sayı eklemek işe yarıyor.

Yalan söyledim, bir tane daha düzenleme

Tamam, kabın yüksekliğine uyacak şekilde çizilebilir bu katmanı manuel olarak nasıl güncelleyeceğinizi öğrendim, tam açıklama burada bulunabilir . Bu kod onCreate () yönteminize eklenmelidir:

final TextView tv = (TextView)findViewById(R.id.image_test);
        ViewTreeObserver vto = tv.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                LayerDrawable ld = (LayerDrawable)tv.getBackground();
                ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
            }
        });

Ve işim bitti! Whew! :)


Bu sorun gradyan dikey olmasıdır. Dikey (yani: yatay bir çizgi) ayrılmış şekle ihtiyacım var, ama yatay olması için degrade gerekir (yani: sola sağa hareket). Bu örnekte, hem ayırıcı hem de gradyan dikeydir.
Andrew

Oh tamam, şimdi söylediklerini anlıyorum. (Görüntüler işte engellendi, bu yüzden sadece telefonumdan sizinki görüntüleyebildim, ayrıntıları iyi söylemek zor). Ne yazık ki buna hazırlıksız bir çözümüm yok, ancak biri yatay gradyanlı, biri yarı opaklıkta yarı boyutunda beyazdan siyaha dikey gradyanlı iki dikdörtgenle çekilebilir bir şekil oluşturabileceğinizi varsayarım, aşağı doğru hizalayın. Bunu nasıl yapacağımla ilgili olarak şu anda herhangi bir spesifik örneğim yok.
Kevin Coppock

Evet, yapmayı umuyordum, ama henüz çözemedim. Yardımın için minnettarım
Andrew

Rica ederim! Bir kez daha denedim ve sanırım aradığın şeyi aldım. Bunları Java üzerinden dinamik olarak yapmanız gerekebilir (yorumlara göre), ancak şu anda sabit boyutlar için hile yapar.
Kevin Coppock

17
En az +10 vermek istediğiniz cevap budur. Cevabınızdaki kavga duygusunu seviyorum: Android API'ya karşı siz kim kazanacak? Hiç bilecek miyiz? ;) Ayrıca, karşılaştığınız tüm tuhaflıkları koruduğunuz için çok kullanışlı bir öğrenme materyali.
andr

28

Bir katman listesi kullanarak xml'deki degrade şekilleri katmanlayabilirsiniz. İkinci öğenin yarı saydam olduğu varsayılan duruma sahip bir düğme düşünün. Bir çeşit vinyet etkisi ekler. (Lütfen özel tanımlı renkleri affedin.)

<!-- Normal state. -->
<item>
    <layer-list>
        <item>  
            <shape>
                <gradient 
                    android:startColor="@color/grey_light"
                    android:endColor="@color/grey_dark"
                    android:type="linear"
                    android:angle="270"
                    android:centerColor="@color/grey_mediumtodark" />
                <stroke
                    android:width="1dp"
                    android:color="@color/grey_dark" />
                <corners
                    android:radius="5dp" />
            </shape>
        </item>
        <item>  
            <shape>
                <gradient 
                    android:startColor="#00666666"
                    android:endColor="#77666666"
                    android:type="radial"
                    android:gradientRadius="200"
                    android:centerColor="#00666666"
                    android:centerX="0.5"
                    android:centerY="0" />
                <stroke
                    android:width="1dp"
                    android:color="@color/grey_dark" />
                <corners
                    android:radius="5dp" />
            </shape>
        </item>
    </layer-list>
</item>


4

Bunu sadece xml şekilleri kullanarak yapabilirsiniz - sadece katman listesi VE negatif dolguları aşağıdaki gibi kullanın:

    <layer-list>

        <item>
            <shape>
                <solid android:color="#ffffff" />

                <padding android:top="20dp" />
            </shape>
        </item>

        <item>
            <shape>
                <gradient android:endColor="#ffffff" android:startColor="#efefef" android:type="linear" android:angle="90" />

                <padding android:top="-20dp" />
            </shape>
        </item>

    </layer-list>

1

Bu yöntemi deneyin, sonra istediğiniz her şeyi yapabilirsiniz.
Bir yığın gibi, bu yüzden hangi öğenin önce veya son olarak geldiğine dikkat edin.

<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="50dp" android:start="10dp" android:left="10dp">
    <shape
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <corners android:radius="3dp" />
        <solid android:color="#012d08"/>
    </shape>
</item>
<item android:top="50dp">
    <shape android:shape="rectangle">
        <solid android:color="#7c4b4b" />
    </shape>
</item>
<item android:top="90dp" android:end="60dp">
    <shape android:shape="rectangle">
        <solid android:color="#e2cc2626" />
    </shape>
</item>
<item android:start="50dp" android:bottom="20dp" android:top="120dp">
    <shape android:shape="rectangle">
        <solid android:color="#360e0e" />
    </shape>
</item>


0

Bir degradeyi, yeşil degrade için opak opaklıkla başka bir görüntünün üzerindeki vurgu için neredeyse saydam bir opaklıkla kaplamayı denediniz mi?


Hayır, sahip değilim, ancak bir degradeyi bir şekil üzerinde diğerinin üzerine nasıl yerleştireceğimi tam olarak bilmiyorum. Şekli android kullanarak bir LinearLayout arka plan olarak kullanıyorum: background = "@ drawable / myshape"
Andrew

Farklı opaklıklara sahip iki şekli üst üste koymak mümkün müdür? (Bilmiyorum.)
Greg D
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.