Wydaje mi się, że nie da się tego zrobić w XML (przynajmniej nie w Androidzie), ale znalazłem zamieszczone tutaj dobre rozwiązanie , 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 umożliwia wybranie wielu przystanków koloru, a poniższa tablica zmiennoprzecinkowa określa, gdzie te przystanki się znajdują (od 0 do 1). Możesz wtedy, jak wspomniano, po prostu użyć tego jako standardowego Drawable.
Edycja: Oto, jak możesz to wykorzystać w swoim scenariuszu. Powiedzmy, że masz Button zdefiniowany w XML w następujący sposób:
<Button
android:id="@+id/thebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press Me!"
/>
Następnie umieściłbyś coś takiego w swojej metodzie onCreate ():
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 po prostu zastąp lub dodaj stopery dla potrzebnych kolorów. Zasadniczo, w moim przykładzie, zacząłbyś od jasnozielonego, przechodzącego do białego nieco przed środkiem (aby uzyskać blaknięcie zamiast ostrego przejścia), zanikającego od białego do średniego zielonego między 45% a 55%, a następnie zanikającego od średnio zielony do ciemnozielonego od 55% do końca. To może nie wyglądać dokładnie tak, jak twój kształt (w tej chwili nie mam możliwości przetestowania tych kolorów), ale możesz to zmodyfikować, aby powtórzyć swój przykład.
Edycja: Również 0, 0, 0, theButton.getHeight()
odnosi się do współrzędnych x0, y0, x1, y1 gradientu. Zasadniczo zaczyna się od x = 0 (lewa strona), y = 0 (na górze) i rozciąga się do x = 0 (chcemy mieć pionowy gradient, więc kąt od lewej do prawej nie jest konieczny), y = wysokość przycisku. Tak więc gradient przebiega pod kątem 90 stopni od góry przycisku do dołu przycisku.
Edycja: OK, więc mam jeszcze jeden pomysł, który działa, haha. Obecnie działa w języku XML, ale powinno być możliwe również w przypadku kształtów w Javie. To trochę skomplikowane i wyobrażam sobie, że istnieje sposób na uproszczenie go do jednego kształtu, ale na razie mam to:
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>
W porządku, więc w zasadzie utworzyłem gradient kształtu w XML dla poziomego zielonego gradientu, ustawiony pod kątem 0 stopni, przechodząc od lewego zielonego koloru górnego obszaru do prawego zielonego koloru. Następnie wykonałem prostokąt kształtu z półprzezroczystą szarością. Jestem prawie pewien, że można to wstawić do XML listy warstw, aby uniknąć tego dodatkowego pliku, ale nie jestem pewien, jak. Ale w porządku, w takim razie w pliku XML lista_warstw pojawia się rodzaj hackerskiej części. Umieszczam zielony gradient jako dolną warstwę, a następnie połowę nakładam jako drugą warstwę, przesuniętą od góry o 50 dp. Oczywiście chciałbyś, aby ta liczba zawsze była o połowę mniejsza od rozmiaru twojego widoku, a nie stałe 50 dp. Nie sądzę jednak, aby można było używać procentów. Stamtąd właśnie wstawiłem TextView do mojego układu test.xml, używając pliku layer_list.xml jako mojego tła.
Tada!
Jeszcze jedna edycja : zdałem sobie sprawę, że możesz po prostu osadzić kształty na liście warstw jako elementy, co oznacza, że nie potrzebujesz już 3 oddzielnych plików XML! Możesz osiągnąć ten sam efekt łącząc je w następujący 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>
W ten sposób możesz ułożyć dowolną liczbę elementów! Mogę spróbować się pobawić i zobaczyć, czy uda mi się uzyskać bardziej wszechstronny wynik dzięki Javie.
Myślę, że to ostatnia edycja ... : OK, więc zdecydowanie możesz naprawić pozycjonowanie za pomocą Java, 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 polegającego na tym, że nie można zmierzyć TextView, dopóki nie zostanie narysowany. Nie jestem jeszcze do końca pewien, jak możesz to osiągnąć ... ale ręczne wstawienie numeru do topInset działa.
Skłamałem, jeszcze jedna edycja
OK, dowiedziałem się, jak ręcznie zaktualizować tę warstwę do rysowania, aby pasowała do wysokości kontenera, pełny opis można znaleźć tutaj . Ten kod powinien znaleźć się w Twojej 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 gotowe! Uff! :)