Jeśli musisz wyświetlić w aplikacji obrazy statyczne, możesz użyć klasy Drawable
i jej podklas do rysowania kształtów oraz
obrazów. Drawable
to ogólna abstrakcja dla:
coś, co można narysować. Różne podklasy pomagają w przypadku konkretnego obrazu
w scenariuszach. Możesz je rozszerzać, aby definiować własne obiekty rysowalne.
które zachowują się
w unikalny sposób.
Poza użyciem konstruktorów klas są jeszcze 2 sposoby definiowania i tworzenia instancji Drawable
:
- Powiększ zasób graficzny (plik bitmapy) zapisany w projekcie.
- Dodaj komponent XML, który określa właściwości możliwe do rysowania.
Uwaga: Zamiast tego możesz użyć obiektu rysowania wektorowego, który definiuje obraz ze zbiorem punktów, linii i krzywych, a także powiązanych informacji o kolorach. Umożliwia to obiekty rysowane wektorowo możliwość skalowania w różnych rozmiarach bez utraty jakości. Więcej informacji znajdziesz w sekcji Wektor elementów rysowanych.
Tworzenie elementów rysunkowych na podstawie obrazów zasobów
Możesz dodać grafikę do swojej aplikacji, odwołując się do pliku graficznego zasobów projektu. Obsługiwane typy plików to PNG (preferowany), JPG (dopuszczalne) i GIF (odradzamy). Ikony, logo aplikacji i inne elementy graficzne, np. używane dobrze nadają się do tej techniki.
Aby użyć zasobu obrazu, dodaj plik do res/drawable/
w katalogu projektu. Gdy Twój projekt znajdzie się w projekcie, możesz odwoływać się do obrazu
z kodu lub układu XML. Tak czy inaczej, jest to użycie
identyfikator zasobu, który jest nazwą pliku bez rozszerzenia typu pliku. Dla:
Określ my_image.png
jako my_image
.
Uwaga: zasoby graficzne umieszczone w pliku
Katalog res/drawable/
może być automatycznie optymalizowany przy użyciu
bezstratna kompresja obrazu wykonywana za pomocą narzędzia aapt
podczas kompilacji
proces tworzenia konta. Może to być na przykład plik PNG w prawdziwym kolorze, który nie wymaga więcej niż 256 kolorów.
można przekonwertować na 8-bitowy plik PNG z paletą kolorów. W efekcie powstanie obraz
takiej samej jakości, ale wymagający mniej pamięci. W efekcie pliki binarne obrazów
umieszczone w tym katalogu mogą ulec zmianie podczas kompilacji. Jeśli planujesz przeczytać
w postaci strumienia bitowego, aby przekonwertować go na format bitmapy, umieść obrazy w
res/raw/
, w którym narzędzie aapt
nie
je modyfikować.
Ten fragment kodu pokazuje, jak utworzyć obiekt ImageView
, w którym
obraz utworzony z zasobu rysowanego i dodany do układu:
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); }
W innych przypadkach zasób obrazu może być obsługiwany jako obiekt Drawable
, jak w tym przykładzie:
przykład:
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);
Ostrzeżenie: każdy unikalny zasób w projekcie.
mogą utrzymywać tylko jeden stan, niezależnie od tego, ile różnych obiektów
utworzyć dla niego instancję. Jeśli na przykład utworzysz instancję 2 obiektów Drawable
z tego samego zasobu obrazu i
zmienisz właściwość (np. alfa) jednego obiektu, to wpłynie to również
z drugiej strony. Gdy mamy do czynienia z wieloma instancjami zasobu graficznego,
bezpośredniego przekształcenia obiektu Drawable
, musisz wykonać
starszy
animację.
Poniższy fragment kodu XML pokazuje, jak dodać zasób rysowalny do elementu ImageView
w układzie XML:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/my_image" android:contentDescription="@string/my_image_desc" />
Więcej informacji o korzystaniu z zasobów projektu znajdziesz w artykule Zasoby.
Uwaga: jeśli jako źródła obiektów rysowanych używasz zasobów graficznych, Zadbaj o to, aby obrazy miały odpowiedni rozmiar przy różnej gęstości pikseli. Jeśli nieprawidłowe obrazy zostaną powiększone, by pasowały, co może spowodować pojawienie się artefaktów w obiektach rysowanych. Więcej informacji znajdziesz w artykule Obsługa różnych opcji gęstości pikseli.
Tworzenie elementów rysunkowych na podstawie zasobów XML
Jeśli występuje Drawable
który chcesz utworzyć, który nie jest początkowo zależny od zmiennych zdefiniowanych przez
lub interakcji użytkownika, dobrym rozwiązaniem będzie zdefiniowanie atrybutu Drawable
w pliku XML. Równomierny
jeśli spodziewasz się, że Drawable
zmieni swoje właściwości podczas interakcji użytkownika
z aplikacją, zastanów się nad zdefiniowaniem obiektu w pliku XML, ponieważ możesz modyfikować właściwości po
Obiekt został utworzony.
Po zdefiniowaniu pliku Drawable
w formacie XML zapisz go w pliku
Katalog res/drawable/
Twojego projektu. Poniższy przykład pokazuje kod XML, który
definiuje
TransitionDrawable
zasób, który dziedziczy z zasobu Drawable
:
<!-- 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>
Następnie pobierz i utwórz instancję obiektu, wywołując
Resources#getDrawable()
i przekazując identyfikator zasobu Twojego pliku XML. Dowolne
Drawable
podklasa
obsługujące metodę inflate()
, można zdefiniować w pliku XML i utworzyć jej instancję
przez Twoją aplikację.
Każda klasa rysowalna, która obsługuje inflację kodu XML, wykorzystuje określone atrybuty XML
które pozwalają zdefiniować właściwości obiektu. Poniższy kod tworzy instancję
TransitionDrawable
i ustawia ją jako treść
Obiekt ImageView
:
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.
Więcej informacji o obsługiwanych atrybutach XML znajdziesz w klasach wymienionych powyżej.
Elementy rysowane kształtami
Obiekt ShapeDrawable
może być dobrym rozwiązaniem
gdy chcesz dynamicznie rysować dwuwymiarową grafikę. Dostępne opcje
automatyczne rysowanie kształtów podstawowych w obiekcie ShapeDrawable
i stosuj style, których potrzebuje Twoja aplikacja.
ShapeDrawable
jest podklasą klasy Drawable
. Dlatego możesz użyć parametru
ShapeDrawable
wszędzie tam, gdzie spodziewana jest wartość Drawable
. Dla:
można na przykład ustawić tło za pomocą obiektu ShapeDrawable
widoku danych, przekazując go do metody setBackgroundDrawable()
widoku. Możesz też narysować kształt
własny widok niestandardowy i dodać go do układu w aplikacji.
ShapeDrawable
ma własną metodę draw()
, więc możesz utworzyć
podklasa View
, która pobiera ShapeDrawable
podczas zdarzenia onDraw()
, jak widać w
ten przykładowy kod:
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); } }
Możesz użyć klasy CustomDrawableView
w przykładowym kodzie
jak każdy inny widok niestandardowy. Możesz na przykład:
automatycznie dodać go do aktywności w aplikacji, jak w tym przykładzie
przykład:
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); }
Jeśli zamiast tego chcesz użyć widoku niestandardowego z układem XML, użyj funkcji
Klasa CustomDrawableView
musi zastąpić konstruktor View(Context, AttributeSet)
, który jest wywoływany, gdy klasa jest
została powiększona z pliku XML. Poniższy przykład pokazuje, jak zadeklarować
CustomDrawableView
w układzie XML:
<com.example.shapedrawable.CustomDrawableView android:layout_width="fill_parent" android:layout_height="wrap_content" />
Klasa ShapeDrawable
, podobnie jak wiele innych
typy rysowalne w pakiecie android.graphics.drawable
pozwalają na
zdefiniować różne właściwości obiektu za pomocą metod publicznych. Przykład
właściwości, które warto dostosować, to przezroczystość alfa, filtr kolorów,
przezroczystość i kolor.
Możesz też definiować podstawowe kształty rysowane za pomocą zasobów XML. Więcej Więcej informacji można znaleźć w sekcji Kształt, który można rysować w Typy zasobów rysowalnych.
Elementy rysowane NinePatch
Grafika NinePatchDrawable
to
rozciągnięty obraz bitmapy, którego można użyć jako tła widoku. Android,
automatycznie zmienia rozmiar grafiki w celu dostosowania jej do zawartości widoku. An
przykład użycia obrazu NinePatch to tło w standardowym Androidzie
Przyciski – muszą się rozciągać, tak aby można było zmieścić ciągi znaków o różnej długości. O
Grafika NinePatch to standardowy obraz PNG z dodatkowym ramką o szerokości 1 piksela.
Musisz go zapisać za pomocą rozszerzenia 9.png
w pliku
Katalog res/drawable/
Twojego projektu.
Użyj obramowania, aby określić rozciągane i statyczne obszary obrazu. Oznaczysz sekcję rozciąganą, rysując co najmniej jeden obszar o szerokości 1 piksela. czarne linie w lewej i górnej części obramowania (pozostałe piksele obramowania powinien być całkowicie przezroczysty lub biały). Możesz mieć tyle rozciąganych sekcji według potrzeb. Względny rozmiar sekcji rozciąganych pozostaje taki sam, więc Największa sekcja zawsze pozostaje największa.
Możesz też zdefiniować opcjonalną rysowaną część obrazu (w ten sposób
linie dopełnienia), rysując linię po prawej stronie i linię na dole. Jeśli
Obiekt View
ustawia grafikę NinePatch jako tło
a następnie określa tekst widoku, rozciąga się tak, że cały tekst
zajmuje tylko obszar wyznaczony przez prawa i dolne linie (jeśli są uwzględnione).
Jeśli nie ma linii dopełnienia, Android używa linii lewej i górnej do
określić ten obszar rysowalny.
Aby ułatwić określenie różnicy między liniami, linia lewa i górna definiują które piksele obrazu mogą być replikowane, aby rozciągać . Linie dolne i prawe określają względny obszar obrazu, który mogą zajmować zawartość widoku.
Ilustracja 1 pokazuje przykład grafiki NinePatch użytej do zdefiniowania przycisku:
Ta grafika NinePatch definiuje jeden rozciągany obszar, który obejmuje górną i lewą stronę oraz linie dolne i prawy obszar, który można rysować. Na obrazie u góry szare przerywane linie wskazują obszary obrazu, które są replikowane aby go rozciągnąć. Różowy prostokąt na obrazku u dołu wskazuje, region, w którym dozwolona jest zawartość widoku. Jeśli nie do tego obszaru, obraz zostanie rozciągnięty, aby je dopasować.
Narzędzie Draw 9-patch oferuje to bardzo przydatny sposób tworzenia obrazów NinePatch, za pomocą grafiki WYSIWYG. redaktorem. Ostrzeżenia są wyświetlane nawet wtedy, gdy region zdefiniowany dla elementu rozciąganego na obszar, gdzie piksel może powstawać artefaktów rysowania. replikacji danych.
Poniższy przykładowy kod XML układu pokazuje, jak dodać grafikę NinePatch
na kilka przycisków. Obraz NinePatch jest zapisywany w
res/drawable/my_button_background.9.png
<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"/>
Pamiętaj, że pola layout_width
i layout_height
atrybuty mają wartość wrap_content
, by przycisk był dobrze dopasowany
wokół tekstu.
Rysunek 2 przedstawia 2 przyciski renderowane z obrazów XML i NinePatch. przedstawione powyżej. Zwróć uwagę, że szerokość i wysokość przycisku zmienia się w zależności od tekstu. a obraz tła zostanie rozciągnięty, aby go dopasować.
Niestandardowe elementy rysowane
Aby utworzyć własne rysunki, możesz to zrobić, rozszerzając klasę Drawable
(lub dowolną jej podklasę).
Najważniejszą metodą jest draw(Canvas)
ponieważ zapewnia to obiekt Canvas
, którego musisz użyć do podania
instrukcje rysowania.
Ten kod pokazuje prostą podklasę klasy Drawable
które tworzy okrąg:
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; } }
Potem możesz dodać obiekt rysowany w dowolnym miejscu, np.
ImageView
jak tutaj:
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));
W Androidzie 7.0 (poziom interfejsu API 24) i nowszych możesz też zdefiniować instancje niestandardowego elementu rysowanego z XML w następujący sposób:
- Używanie pełnej i jednoznacznej nazwy klasy jako nazwy elementu XML. W tym podejściu
Klasa obiektowa do rysowania musi być publiczną klasą najwyższego poziomu:
<com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android" android:color="#ffff0000" />
- użycie
drawable
jako nazwy tagu XML i określenie w pełni kwalifikowanej klasy. nazwa z atrybutu class. Tę metodę można stosować zarówno w przypadku publicznych klas najwyższego poziomu, jak publiczne statyczne klasy wewnętrzne:<drawable xmlns:android="http://schemas.android.com/apk/res/android" class="com.myapp.MyTopLevelClass$MyDrawable" android:color="#ffff0000" />
Dodaj odcień do elementów, które można rysować
W Androidzie 5.0 (poziom interfejsu API 21) lub nowszym można zabarwić mapy bitowe i 9 poprawek zdefiniowane jako
przez maski alfa. Możesz zabarwić je za pomocą zasobów kolorów lub atrybutów motywu, które mają kolor
zasobów (na przykład ?android:attr/colorPrimary
). Zwykle tworzysz te komponenty
tylko raz i automatycznie pokolorować je, by pasowały do motywu.
Możesz zastosować odcień w odcieniach BitmapDrawable
, NinePatchDrawable
i VectorDrawable
za pomocą metody setTint()
. Dostępne opcje
możesz też ustawić kolor i tryb odcienia w układach za pomocą przycisków android:tint
android:tintMode
.
Wyodrębnij z obrazu najważniejsze kolory
Biblioteka pomocy Androida zawiera klasę Palette
, która umożliwia wyodrębnianie z obrazu dobrze widocznych kolorów.
Możesz załadować elementy rysowane jako obiekt Bitmap
i przekazać je usłudze Palette
, aby uzyskać dostęp do kolorów.
Więcej informacji można znaleźć w sekcji Wybieranie kolorów za pomocą
Palette API.