2013-07-05 7 views
8

Załóżmy, że mamy niestandardowy ListView, który rozszerza metodę onDraw() przez narysowanie w niej jakiegoś prostokąta.Jak nakładać kolor tekstu na liście w określonym regionie?

class Listpicker extends ListView { 
//..Some other methods here..// 
    @Override 
    protected void onDraw(android.graphics.Canvas canvas) { 
    super.onDraw(canvas); 
    canvas.drawBitmap(glassPickerBitmap, null, glassRect, semiTransparrentPaint); 
    } 
} 

bitmapy sporządzony stanowią jakiś szkła, które jest prostokątem o szerokości równej szerokości pogrupowanych i niektóre wysokości. To, czego chcę, to gdy element listy przewija się do tego prostokąta, kolor używany do rysowania tekstu (nie wszystkie elementy z tłem itp.) Zostałyby zmienione na inny kolor. Tak więc, na przykład, gdy element listy jest dopasowany tak, że tylko połowa wysokości tekstu pasuje do glassPickerBitmap, zewnętrzna część elementu listy powinna pozostać w swoich kolorach porządkowych, a część znajdująca się w środku glassPickerBitmap powinna zmienić kolor tekstu. Elementy listy są prostymi widokami tekstowymi bez żadnego tła.

Jak można to osiągnąć? Może każdy ColorFilter s jest przypisany do Paint? Ale gdzie? onDraw() metoda Listview nie jest wywoływana nawet po przewinięciu ListView ... Czy można to zrobić w niestandardowych widokach, na przykład, które będą elementami ListView? Lub może być trochę Color/Shader/nie wiem, co jeszcze można użyć nakładki tutaj, ale gdzie?

EDIT (dodawane przykładów zdjęcia)

Oto przykład pewnych upraw z APP rzeczywistych. Istnieją 2 ListView s: jeden po lewej stronie, drugi po prawej. Szkło to szary prostokąt. Teraz wybrana jest wybrana z lewej listy "dolar amerykański". I przewijam w prawo ListView w ten sposób, że wybór jest gdzieś pomiędzy USD i Afghan Afghani. Teraz chcę, aby USD waluta po lewej stronie ListView byłaby narysowana na czerwono (dokładny kolor nie ma znaczenia, zmienię go później na coś znaczącego) ORAZ, w tym samym czasie, dolna część "Dolar amerykański" i górna część "Afghan Afghani" w prawej ListView zostanie narysowany również w tym samym czerwonym kolorze.

Ta zmiana koloru powinna być wykonywana w sposób dynamiczny - kolor powinien być zmieniany tylko dla części tekstu, która jest pod szklanym prostokątem podczas przewijania listy.

* OK, EUR i USD są tutaj specjalnymi walutami narysowanymi w niestandardowym kolorze cyjan. Pytanie dotyczy co najmniej tekstu o kolorze biały. Ale jeśli będzie można zmienić również kolor cyjan, byłoby świetnie.

List example

+0

'View.setWillNotDraw' (logiczna willNotDraw) powinien dostać' onDraw' nazwie w 'ListView'. To, czy pozwoli ci to osiągnąć to, co chcesz, jest dyskusyjne. Interesujące pytanie jednak. – techiServices

+0

@Prizoff możesz podać dwa zdjęcia (jeden z przedmiotów zwykłych i drugi z przedmiotu pod szkłem)? – eveliotc

+0

@EvelioTarazona zrobione – Prizoff

Odpowiedz

3

Jak widać w ich realizacji, których używają i aktualizować stałą pozycję w ich ListAdapter tak potem zaktualizować View pasujący odpowiednio, co jest dla mnie najłatwiejsze i prostszy sposób to zrobić, ale nie dostać pół-pół kolorowy tekst, który myślę, że nadal chcesz :)


http://i.imgur.com/jHvuBcL.png

Więc tutaj jest prawdopodobnie jednym z najgorszych Dałem odpowiedzi, przepraszam o tym, będę prawdopodobnie ponownie tego czy nadzieję, że ktoś może skierować Cię do lepszego rozwiązania

Można zobaczyć rozmyte demo pod adresem:

http://telly.com/Y98DS5

Brudna sposób :

  • Tworzenie Paint z właściwego ColorMatrixColorFilter, w celu udzielenia odpowiedzi na to jestem po prostu desaturacji, musisz dowiedzieć się swoją macierz 5x4 dla ColorMatrix uzyskać cyjan szukasz. Będziesz także potrzebował jakiś Rect s, aby zdefiniować źródło i dest, kiedy rysujesz poniżej.
  • Załóż ekran off Bitmap i Canvas której możesz użyć, aby narysować swoją listę, która jest wykonana w onSizeChanged więc mamy odpowiednie wartości Widok układu, tutaj można rozpocząć zauważając zabrudzenia jak trzeba będzie przeznaczyć Bitmap tak duży jak Twój ListView, więc możesz uzyskać OutOfMemoryException.
  • Zastąp draw korzystać z offu Canvas i niech ListView draw do niego, a następnie można wyciągnąć Bitmap do danego Canvas że opracuje listę jak zwykle, po czym wyciągnąć tylko część tego Bitmap który zostanie sporządzony inaczej używając Paint, które zdefiniowaliśmy wcześniej, otrzymasz overdraw na te piksele.
  • Na koniec narysuj swoje prefabrykowane szkło Bitmap, polecam n-plaster (9-plaster), dzięki czemu skaluje się i wygląda ostro na różnych ekranach i gęstościach, a następnie uzyskać więcej overdraw dla tych pikseli.

Całe ciasto wygląda tak:

public class OverlayView extends ListView { 
    private RectF mRect; 
    private Rect mSrcRect; 
    private Paint mPaint; 

    private Canvas mCanvas; 
    private Bitmap mBitmap; 
    private float mY; 
    private float mItemHeight; 

    public OverlayView(Context context) { 
    super(context); 

    initOverlay(); 
    } 

    public OverlayView(Context context, AttributeSet attrs) { 
    super(context, attrs); 

    initOverlay(); 
    } 

    public OverlayView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 

    initOverlay(); 
    } 

    private void initOverlay() { 
    // DO NOT DO THIS use attrs 
    final Resources res = getResources(); 
    mY = res.getDimension(R.dimen.overlay_y); 
    mItemHeight = res.getDimension(R.dimen.item_height); 
    // 
    mRect = new RectF(); 
    mSrcRect = new Rect(); 
    mPaint = new Paint(); 

    ColorMatrix colorMatrix = new ColorMatrix(); 
    colorMatrix.setSaturation(0); 
    mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); 
    } 

    @Override 
    public void draw(Canvas canvas) { 
    super.draw(mCanvas); 
    canvas.drawBitmap(mBitmap, 0, 0, null); 

    canvas.drawBitmap(mBitmap, mSrcRect, mRect, mPaint); 
    } 

    @Override 
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
    super.onSizeChanged(w, h, oldw, oldh); 

    mRect.set(0, mY, w, mY + mItemHeight); 
    mRect.roundOut(mSrcRect); 

    mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
    mCanvas = new Canvas(mBitmap); 
    } 
} 

Więc powiedział, że mam nadzieję, że skończy się czystsze rozwiązanie, nawet jeśli nie dostać tego pół-pół seksapil :)

+0

Yup Używam Max OS X właśnie Maverixks – eveliotc

+0

Co powiesz na używanie 'getDrawingCache()' zamiast oddzielnej bitmapy? –

+0

@ S.D. jeśli możesz go również użyć, w rzeczywistości robi coś podobnego, przychodzi tylko z dodatkowymi dziwactwami, takimi jak obecnie nieaktualny maksymalny rozmiar pamięci podręcznej, puste bitmapy, ktoś inny może również używać tego rysunku podręcznego i jak pamiętam, powinieneś go używać tylko w przypadku warstw oprogramowania, w tym przypadku (nie zawsze) zarządzanie własną pamięcią podręczną daje kontrolę i spokój: wiesz na pewno, że to twoja wina;) tak czy inaczej, jak już wspomniałem, to jest brudne i powinieneś tego unikać (najgorsze sprzedawca kiedykolwiek) – eveliotc

1

Po pierwsze, należy zapasowy bitmapę i płótna:

class Listpicker extends ListView { 
    Bitmap bitmapForOnDraw = null; 
    Canvas canvasForOnDraw = null; 

Upewnij się, że jest to odpowiedni rozmiar:

@override 
    protected void onSizeChanged (int w, int h, int oldw, int oldh) { 
     if (bitmapForOnDraw != null) bitmapForOnDraw.recycle(); 
     bitmapForOnDraw = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
     canvasForOnDraw = new Canvas(bitmapForOnDraw); 
    } 

A kiedy przyjdzie do rysowania listę:

@override 
    protected void onDraw(android.graphics.Canvas realCanvas) { 
     // Put the list in place 
     super.onDraw(realCanvas); 

     // Now get the same again 
     canvasForOnDraw.drawColor(0x00000000, PorterDuff.Mode.CLEAR); 
     super.onDraw(canvasForOnDraw); 
     // But now change the colour of the white text 
     canvasForOnDraw.drawColor(0xffff00ff, PorterDuff.Mode.MULTIPLY); 

     // Copy the different colour text into the right place 
     canvas.drawBitmap(bitmapForOnDraw, glassRect, glassRect overwritePaint); 

     // finally, put the box on. 
     canvas.drawBitmap(glassPickerBitmap, null, glassRect, semiTransparrentPaint); 
    }