Kształty wielowarstwowe

Chciałbym stworzyć kształt podobny do poniższego obrazka:

alt text

Zwróć uwagę, że górna połowa gradientu gradientu od koloru 1 do koloru 2, ale jest dolna połowa, która gradientu od koloru 3 do koloru 4. Wiem, jak zrobić kształt z jednym gradientem, ale nie jestem pewien, jak podzielić kształt na dwie połówki i zrobić 1 kształt z 2 różnymi gradientami.

Jakieś pomysły?

Author: Andrew, 2010-12-07

5 answers

Myślę, że nie da się tego zrobić w XML( przynajmniej Nie w Androidzie), ale znalazłem dobre rozwiązanie opublikowane tutaj , które wygląda na to, że byłoby to bardzo pomocne!

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

Zasadniczo, tablica int pozwala na wybranie wielu zatrzymań kolorów, a następująca tablica float określa, gdzie są one umieszczone (od 0 do 1). Można wtedy, jak podano, po prostu użyć tego jako standardowego Drawable.

Edit: oto jak możesz tego użyć w swoim scenariuszu. Powiedzmy, że masz guzik. zdefiniowane w XML tak:

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

W metodzie onCreate() umieściłbyś coś takiego:

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

Nie mogę tego w tej chwili przetestować, to jest kod z mojej głowy, ale w zasadzie wystarczy wymienić, lub dodać przystanki dla kolorów, których potrzebujesz. Zasadniczo, w moim przykładzie, można zacząć od jasnozielonego, blaknięcie do bieli nieco przed środkiem (aby dać blaknięcie, a nie ostre przejście), blaknięcie od bieli do średniej zieleni między 45% i 55%, a następnie blaknięcie od średniej zieleni do ciemności Zielony od 55% do końca. Może to nie wygląda dokładnie tak jak twój kształt (w tej chwili nie mam możliwości testowania tych kolorów), ale możesz zmodyfikować to, aby odtworzyć swój przykład.

Edit: również 0, 0, 0, theButton.getHeight() odnosi się do współrzędnych x0, y0, x1, y1 gradientu. W zasadzie zaczyna się od x = 0( lewa strona), y = 0 (góra) i rozciąga się do x = 0 (chcemy pionowego gradientu, więc nie jest potrzebny kąt od lewej do prawej), y = wysokość przycisku. Więc gradient idzie pod kątem 90 stopni od góry przycisku do dołu przycisku.

Edit: Ok, więc mam jeszcze jeden pomysł, który działa, haha. W tej chwili działa w XML, ale powinien być wykonalny również dla kształtów w Javie. To trochę skomplikowane i wyobrażam sobie, że istnieje sposób, aby uprościć go do jednego kształtu, ale to jest to, co mam do teraz:

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>

Okej, więc w zasadzie stworzyłem gradient kształtu w XML dla poziomego Zielonego gradientu, ustawionego pod kątem 0 stopni, przechodzącego od lewego zielonego koloru górnego obszaru do prawego zielonego koloru. Następnie wykonałam kształt prostokąta z połową przezroczystej szarości. Jestem pewien, że to może być wplecione w layer-list XML, ale nie wiem jak. Ale OK, wtedy rodzaj hacky część wchodzi w pliku XML layer_list. Kładę zielony gradient jako dolną warstwę, a następnie nakładkę pół jako drugą warstwę, przesuniętą od góry o 50dp. Oczywiście chciałbyś, aby ta liczba zawsze była o połowę mniejsza niż rozmiar widoku, a nie stała 50dp. Nie sądzę jednak, że możesz użyć procentów. Stamtąd właśnie wstawiłem TextView do mojego testu.xml layout, używając layer_list.plik xml jako moje tło. Ustawiłem wysokość na 100dp( dwa razy większy od przesunięcia nakładki), co daje:

alt text

Tada!

Jeszcze jedna edycja: zdałem sobie sprawę, że możesz po prostu osadzić kształty na liście warstw rysowanych jako elementy, co oznacza, że nie potrzebujesz już 3 oddzielnych plików XML! Można osiągnąć ten sam wynik łącząc je w ten sposób:

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>

Możesz warstwy tyle przedmiotów, jak chcesz w ten sposób! Może spróbuję się pobawić i zobaczyć, czy Mogę uzyskać bardziej wszechstronny wynik poprzez Javę.

To chyba ostatnia edycja...: ok, więc zdecydowanie możesz naprawić pozycjonowanie poprzez Javę, jak poniżej:

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

Jednak! Prowadzi to do kolejnego irytującego problemu, ponieważ nie można zmierzyć widoku tekstu, dopóki nie zostanie on narysowany. Nie jestem jeszcze pewien, jak możesz to osiągnąć...ale ręczne wstawianie numeru dla topInset działa.

I lied, one more edit

Ok, dowiedzieliśmy się jak ręcznie zaktualizować tę warstwę, aby dopasować ją do wysokości kontenera, pełny opis można znaleźć tutaj . Ten kod powinien zostać użyty w metodzie onCreate ():

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

I skończyłem! Whew! :)

 364
Author: kcoppock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-15 18:20:59

Można warstwować kształty gradientu w xml za pomocą listy warstw. Wyobraź sobie przycisk ze stanem domyślnym jak poniżej, gdzie drugi element jest półprzezroczysty. Dodaje coś w rodzaju winietowania. (Proszę wybaczyć niestandardowe kolory.)

<!-- 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>

 25
Author: LordParsley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-12 15:29:53

Możesz to zrobić używając tylko kształtów xml - wystarczy użyć layer-list i negative padding w następujący sposób:

    <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>
 2
Author: konmik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-24 13:32:07

Czy próbowałeś nałożyć jeden gradient z prawie przezroczystym kryciem dla podświetlenia na inny obraz z nieprzezroczystym kryciem dla zielonego gradientu?

 1
Author: Greg D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-07 20:12:33

Wypróbuj tę metodę, a potem możesz zrobić wszystko, co chcesz.
To jest jak stos więc uważaj, który element jest pierwszy lub ostatni.

<?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
Author: Khalid Ali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-02 17:08:11