Jako dzisiejszą ciekawostkę chcę przedstawić pewną technikę, która może być przydatna przy implementacji systemu GUI na przykład na potrzeby gier. Zazwyczaj bowiem elementami interfejsu są różnego rodzaju kontrolki, które – chociaż nierzadko nie przypominają klasycznych widgetów w rodzaju przycisków czy pól tekstowych – posiadają prostokątne obramowanie. Ta ramka musi mieć jedną istotną cechę: powinna dopasowywać się do rozmiaru kontrolki, dopuszczając elementy o dowolnie dużych wymiarach. A jednocześnie powinna ona być utrzymana w odpowiednim stylu graficznym, zwykle spójnym z resztą aplikacji lub gry.
Sposobem na sprostanie tym wymaganiom jest podział prostokąta kontrolki na dziewięć części, różniących się zakresem skalowania, jakiemu są poddawane, gdy kontrolka zmienia rozmiary. Wśród tych części możemy mianowicie znaleźć następujące:
Żeby więc poprawnie narysować naszą kontrolkę, potrzebujemy w ogólności aż dziewięciu różnych obrazków. Oczywiście niekiedy będzie ich mniej, jeśli sprytnie posłużymy się obrotami i odbicia obrazów. Prawie na pewno jednak będzie to więcej niż jeden sprite i każdy z nich trzeba będzie jakoś oznaczyć i zapisać razem z naszą aplikacją, wymyślając do tego mniej lub bardziej skomplikowaną konwencję.
To, co chcę przedstawić, to w gruncie rzeczy taka właśnie konwencja. Nazywa się ona nine-patch images, czyli tytułowe obrazki dziewięciołatkowe. Pochodzi ona z systemu Android i jest jedną z wielu może mało efektownych, ale pomysłowych rozwiązań, ukrytych w jego API.
Idea jest dość prosta. Jeśli mamy już obramowanie w postaci obrazka otoczonego nim prostokąta, nie musimy wycinać z niego poszczególnych części i zapisywać ich osobno. Zamiast tego zaznaczamy je bezpośrednio na obrazku, dodając wpierw jednopikselowe, czarno-białe obramowanie. Czarny fragment określa część podlegającą skalowaniu (czyli środek), zaś biały – niezmieniające rozmiaru mu rogi prostokąta. Najlepiej widać to na ilustracji po lewej stronie.
Można na niej zauważyć, że do określenia obszaru skalowania wystarczy zasadniczo jeden dodatkowy rząd i jedna dodatkowa kolumna pikseli. Pozostała część dodatkowego obramowania może nam wtedy posłużyć do zdefiniowania obszaru treści, czyli tego fragmentu kontrolki, który będzie mógł być wypełniony tekstem i innymi elementami, ustawionymi jako jej zawartość. Obszar treści nie musi pokrywać się z obszarem skalowania, co z kolei jest widoczne na obrazku po prawej stronie.
Z tak przygotowanej grafiki wciąż możemy w miarę łatwo odczytać programowo potrzebne informacje o sposobie rysowania obramowania kontrolki i wypełniania jej treści. Rozwiązanie to ma przy tym tę oczywistą zaletę, że przygotowanie takiej grafiki jest z pewnością mniej pracochłonne i kłopotliwe niż tworzenie od 3 do 9 osobnych sprite‘ów i podawanie informacji o obszarze treści w jakiegoś rodzaju pliku konfiguracyjnym.
Jeśli więc ktoś w ramach silnikologii stosowanej zajmuje się implementacją modułu GUI, może rozważyć zastosowanie podobnego systemu :)
iPhone ma coś podobnego (podajesz wymiary pionowych i poziomych obramowań i SDK czaruje przy rysowaniu). Ale żeby nie było za lekko, to graficy zawsze wymyślą takie tło przycisku żeby i tak się nie dał rozciągnąć ;)
Sprytne.
Świetne rozwiązanie, posiadające tylko jedną wadę: znaczną różnicę wyglądu pomiędzy małym i dużym elementem danego typu – wystarczy porównać przycisk “OK” i przycisk posiadający dwulinijkowy tekst ;-)
Jako świetne uzupełnienie tego rozwiązania sprawdza się wszelkiego rodzaju grafika wektorowa, renderowana do odpowiedniej rozdzielczości w chwili, gdy jest potrzebna. Np. popularne SVG.
no i na stronach internetowych tez sie tego uzywa :P
No chyba właśnie niespecjalnie – na stronach musisz sobie podzielić swoją ramkę na te 8 czy 9 części :)
Ja zwykle tworzę takiego sprite’a oddzielając poszczególne elementy kreską o jakimś kolorze (np. wściekłoróżowy). Wydaje mi się to trochę wygodniejsze, ale ma tą oczywistą wadę, że takiego koloru raczej nie użyjemy do rysowania samej ramki.
Na stronach rzadko się takie coś spotyka, ale zdarza się. CSS jest wielki =p
Przy tworzeniu stron możemy sobie łatwo zrobić taki feature prostym skryptem w PHP, z użyciem biblioteki GD.