2013-06-13 10 views
5

Mam niestandardowy widok, który szybko nauczyłem się nie robić alokacji obiektów i przenosiłem wszystkie moje przydziały Malowania na inną metodę, dobrze.Unikanie przydziałów obiektów w onDraw() (StaticLayout)?

Potrzebuję użyć StaticLayout jednak dla niektórych tekstów, które miały pewne spannable "stuff" stosowane.

layoutBpm = new StaticLayout(bpmValue, 
      textPaintBPM, arcRadius, Layout.Alignment.ALIGN_NORMAL, 0, 1, 
      false); 

    layoutBpm.draw(canvas); 

Wydawało mi się, że mam to na Drafcie, ale ostrzega mnie, aby tego uniknąć. Ważne jest dla mnie, że robię wszystko, co mogę, aby uniknąć problemów z wydajnością, więc staram się to zrobić właściwie.

Nie mogę znaleźć żadnej dokumentacji, którą mogę zrozumieć, która wyjaśnia, co faktycznie robią niektóre parametry StaticLayout (float spacingmult? Float spacingadd?), Ale trzecia z nich to chyba maksymalna szerokość tekstu StaticLayout które mogę uzyskać tylko dzięki narzędziu onMeasure, ponieważ odnosi się ono do rozmiaru płótna. To pozostawia mnie chcąc umieścić zadanie w Naśladowaniu lub na Drafcie, z których żaden nie wydaje mi się, że powinienem to zrobić. Czy można ustawić zadanie StaticLayout na onDraw, czy jest lepszy sposób na zrobienie tego?

Mam nadzieję, że to ma sens, jestem bardzo nowy w tym. Dziękuję za pomoc.

(edit: Zakładam umieszczenie tego zadania w metodzie i dzwonisz OnDraw/onMeasure jest po prostu głupie i zatrzyma Eclipse ostrzegając mnie, ale przyzwyczajenie faktycznie pomóc)

Odpowiedz

5

Powodem ostrzeżenia jest, ponieważ bardzo często nie trzeba wielokrotnie odtwarzać obiektu podczas operacji rysowania. onDraw() można nazwać setki razy w porównaniu do innych metod w View. W większości przypadków odtworzone obiekty są odtwarzane przy użyciu dokładnie określonych parametrów. Innym razem po prostu mniej narzutów zmienia stan obiektu niż tworzenie nowego obiektu.

W przypadku StaticLayout wystarczy utworzyć nowy, gdy tekst się zmieni lub gdy dostosujesz wypełnienie, odstępy lub szerokość. Jeśli tekst zmienia się często, możesz rozważyć DynamicLayout, który za każdym razem będzie się odnawiał. Kosztuje więcej kosztów niż tworzenie nowego obiektu, ale nie ma mowy, by zdarzało się to częściej niż rozmowy onDraw().

Jeśli tekst nie zmienia się często i absolutnie MUSISZ użyć StaticLayout, możesz uciec z czymś takim jak ta struktura.

StaticLayout myLayout; 
String textSource = defaultSource; 
Paint textPaint = defaultPaint; 
int textWidth = defaultWidth; 

public CustomView(Context ctx) { 
    super(ctx); 
    createLayout(); 
} 

public void setText(String text) { 
    textSource = text; 
    createLayout(); 
} 

public void setWidth(int width) { 
    textWidth = width; 
    createLayout(); 
} 

@Override 
public void onDraw(Canvas canvas) { 
    myLayout.draw(canvas); 
} 

private void createLayout() { 
    myLayout = new StaticLayout(textSource, textPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 0, 1, false); 
} 

Zasadniczo, gdy coś się zmienia, tworzy się nowy układ. W przeciwnym razie ponownie wykorzystaj ostatni utworzony obiekt.

EDIT:

Jednym ze sposobów, aby pominąć podanie środka jest zadzwonić View#measure na nowo przeskalowane samego widoku. Więc twoja metoda createLayout() byłaby podobna do tej.

private void createLayout() { 
     myLayout = new StaticLayout(textSource, textPaint, textWidth, Layout.Alignment.ALIGN_NORMAL, 0, 1, false); 
     int textWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth, MeasureSpec.AT_MOST); 
     int textHeightSpec = MeasureSpec.makeMeasureSpec(maxLayoutHeight, MeasureSpec.AT_MOST); 
     myLayout.measure(textWidthSpec, textHeightSpec); 
     forceLayout(); 
    } 

Zasadniczo to, co to robi, określa układ maksymalnego widoku. Zmierzy się i to dzieci. Funkcja forceLayout() zostanie wywołana na obiekcie nadrzędnym (Twój widok niestandardowy), który zmieni układ innych treści na podstawie nowych pomiarów.

Należy zauważyć, że nigdy nie robiłem tego z StaticLayout, więc nie mam pojęcia, co się stanie. Wygląda na to, że ten typ pomiaru może być już obsługiwany podczas tworzenia widoku, ale może nie.

Mam nadzieję, że to pomoże.

+0

Dziękuję, to dało mi nieco nowy sposób patrzenia na rzeczy. Jedynym problemem, który mam do wykonania powyżej jest to, że 'textPaint' opiera się na' onMeasure() 'już jest wywoływanym (tekst jest skalowany zgodnie z rozmiarem płótna), podobnie jak" textWidth "(który określa kiedy tekst będzie zawijany), więc nie mogę zrobić 'createLayout()' w konstruktorze dla pierwszego przeglądania. Mogę umieścić go w 'onMeasure()', który według mnie nie jest tak często wywoływany? – Anthony

+0

Tekst faktycznie zmienia DUŻO, widok, nad którym pracuję, jest w rzeczywistości okólnym SeekBarem, który zrobiłem, a StaticLayout jest używany do tekstu w środku, który odnosi się do postępu SeekBar. Podczas przeciągania palcem po okręgu wartość zmienia się stale. Pomyślałem, że chociaż wartość zmienia się bardzo, długość jest zawsze dopełniana do trzech cyfr, więc układ nigdy nie musiałby się dopasowywać, więc StaticLayout byłby w porządku. Mogę znaleźć tak mało dokumentacji na układach statycznych/dynamicznych, więc nie jestem pewien, czy to jest poprawne. Każda pomoc ponownie doceniona. – Anthony

+0

W końcu (jak sądzę), zamieniłem 'onMeasure()' na 'onSizeChanged()' ponieważ moje potrzeby w zakresie układu są proste i umieszczam początkowe wywołanie 'createLayout()' zamiast 'onMeasure()'. Lint wydaje się nie mieć nic przeciwko przypisywaniu obiektów w 'onSizeChanged()' z jakiegoś powodu, ale nie lubi go w 'onMeasure()'. Wyobrażam sobie, że obie te metody są nazywane taką samą ilość razy, więc nie mam pojęcia, dlaczego jest w porządku w jednym, a nie w drugim, ale cokolwiek, wydaje się w porządku. Moją główną obawą było uzyskanie alokacji z 'onDraw()', którą zrobiłem. Dzięki jeszcze raz. – Anthony

Powiązane problemy