Jak utworzyć ListView z zaokrąglonymi narożnikami w systemie Android?

176

Jak utworzyć ListView z zaokrąglonymi narożnikami w systemie Android?

Legenda
źródło
To pytanie jest bardzo przydatne, tak samo jak twoja odpowiedź .. !!
Sajad Karuthedath

Odpowiedzi:

371

Oto jeden ze sposobów na zrobienie tego (dzięki Dokumentacji Androida!):

Dodaj następujące elementy do pliku (powiedzmy customshape.xml), a następnie umieść je w (res / drawable / customshape.xml)

<?xml version="1.0" encoding="UTF-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
     android:shape="rectangle"> 
     <gradient 
         android:startColor="#SomeGradientBeginColor"
         android:endColor="#SomeGradientEndColor" 
         android:angle="270"/> 

    <corners 
         android:bottomRightRadius="7dp" 
         android:bottomLeftRadius="7dp" 
         android:topLeftRadius="7dp" 
         android:topRightRadius="7dp"/> 
</shape> 

Gdy skończysz tworzyć ten plik, po prostu ustaw tło w jeden z następujących sposobów:

Poprzez kod: listView.setBackgroundResource(R.drawable.customshape);

Za pomocą XML wystarczy dodać następujący atrybut do kontenera (np. LinearLayout lub do dowolnych pól):

android:background="@drawable/customshape"

Mam nadzieję, że ktoś uzna to za przydatne ...

Legenda
źródło
2
Dzięki za wspaniałą poradę. Do Twojej wiadomości, kopiowanie i wklejanie dało mi wyjątek w czasie wykonywania, mówiąc: „XmlPullParserException: tag linii 4 pliku binarnego XML <gradient> wymaga, aby atrybut„ angle ”był wielokrotnością 45". Łatwo temu zaradzić, zmieniając kąt na 270.
allclaws
Dzięki za naprawę ... Ale nie wiem, dlaczego tak się mogło dziać ... Znalazłeś jakiś konkretny powód?
Legend
@teedyay: Anytime kolego :)
Legend
1
tak samo jak allclaws, kąt powinien być wielokrotnością 45: „XmlPullParserException: binarny plik XML linii # 4 tag <gradient> wymaga, aby atrybut„ angle ”był wielokrotnością 45”
Youssef
29
Nie działa to jednak dobrze z podświetlaniem zaznaczenia: gdy wybrany jest górny lub dolny element, jego kolorowe tło jest prostokątne i narysowane na górze tła z zaokrąglonymi rogami.
Kris Van Bael
56

Chociaż to zadziałało, usunęło również cały kolor tła. Szukałem sposobu, aby zrobić tylko obramowanie i po prostu zastąpić ten kod układu XML tym kodem i było dobrze!

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke android:width="4dp" android:color="#FF00FF00" />
    <padding android:left="7dp" android:top="7dp"
            android:right="7dp" android:bottom="7dp" />
    <corners android:radius="4dp" />
</shape> 
Kevin Parker
źródło
Sprawdź również tę odpowiedź
ThomasRS
12

@ kris-van-bael

Dla tych, którzy mają problemy z podświetleniem wyboru w górnym i dolnym wierszu, gdzie prostokąt tła pojawia się po zaznaczeniu, musisz ustawić selektor widoku listy na przezroczysty kolor.

listView.setSelector(R.color.transparent);

W color.xml po prostu dodaj następujące -

<color name="transparent">#00000000</color>
alvins
źródło
5
to nie zadziałało dla mnie. Dodałem jednak następującą linię i się jej pozbyłem:android:cacheColorHint="@android:color/transparent"
cesar
1
To zdecydowanie rozwiązało problem z wyborem - dzięki! Możesz także użyć android.R.color.transparent dla koloru selektora zamiast tworzyć własny.
greg7gkb
3
Zamiast robić to programowo, dodaj to do swojego ListView w układzie XML, aby ukryć kolor zaznaczenia: android: listSelector = "# 00000000"
Elad Nava
@alvins Czy istnieje sposób na wybranie układu do podświetlania, takiego jak element widoku listy?
Bharat Dodeja
co powinienem zrobić, jeśli chcę użyć nieprzezroczystego koloru dla listSelector?
suitianshi,
3

Dzięki autorom pozostałe odpowiedzi są bardzo przydatne!

Ale nie mogłem zobaczyć, jak dostosować prostokąt, podświetlając element po zaznaczeniu, zamiast wyłączać podświetlanie @alvins @bharat dojeha.

Poniższe działa dla mnie, aby utworzyć zaokrąglony kontener elementów widoku listy bez konturu i jaśniej szarego po wybraniu tego samego kształtu:

Twój xml musi zawierać selektor, taki jak np. (W res / drawable / customshape.xml):

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" >
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
        <stroke android:width="8dp" android:color="@android:color/transparent" />
        <padding android:left="14dp" android:top="14dp"
                android:right="14dp" android:bottom="14dp" />
        <corners android:radius="10dp" />
        <gradient 
             android:startColor="@android:color/background_light"
             android:endColor="@android:color/transparent" 
             android:angle="225"/> 
    </shape>
</item>
<item android:state_pressed="false">
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
        <stroke android:width="8dp" android:color="@android:color/transparent" />
        <padding android:left="14dp" android:top="14dp"
                android:right="14dp" android:bottom="14dp" />
        <corners android:radius="10dp" />
        <gradient 
             android:startColor="@android:color/darker_gray"
             android:endColor="@android:color/transparent" 
             android:angle="225"/> 
    </shape>        
</item>

Następnie należy zaimplementować adapter listy i zastąpić metodę getView, aby ustawić selektor niestandardowy jako tło

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //snip
        convertView.setBackgroundResource(R.drawable.customshape);
        //snip
    }

i muszę również `` ukryć '' domyślny prostokąt selektora, np. w onCreate (ukrywam również cienką szarą linię podziału między elementami):

listView.setSelector(android.R.color.transparent);
listview.setDivider(null);

Takie podejście rozwiązuje ogólne rozwiązanie dla obiektów rysunkowych, a nie tylko ListViewItem z różnymi stanami wyboru.

dr_g
źródło
3

Aktualizacja

Obecnie rozwiązaniem jest użycie wbudowanej CardViewobsługi zaokrąglonych narożników.


Oryginalna odpowiedź *

Innym sposobem, jaki znalazłem, było zamaskowanie układu przez narysowanie obrazu na górze układu. To może ci pomóc. Sprawdź zaokrąglone, przycięte rogi XML w systemie Android

Richard Le Mesurier
źródło
2

Jeszcze inne rozwiązanie zaznaczania problemów z pierwszą i ostatnią pozycją na liście:

Dodaj wypełnienie na górze i na dole tła listy równe lub większe niż promień. Zapewnia to, że podświetlenie zaznaczenia nie pokrywa się z krzywymi narożników.

Jest to najłatwiejsze rozwiązanie, gdy potrzebujesz nieprzejrzystego podświetlenia zaznaczenia.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="@color/listbg" />
    <stroke
        android:width="2dip"
        android:color="#D5D5D5" />
    <corners android:radius="10dip" />

    <!-- Make sure bottom and top padding match corner radius -->
    <padding
        android:bottom="10dip"
        android:left="2dip"
        android:right="2dip"
        android:top="10dip" />
</shape>
William Morrison
źródło
1

To było dla mnie niesamowicie przydatne. Chciałbym zasugerować inne obejście, aby idealnie podkreślić zaokrąglone rogi, jeśli używasz własnegoCustomAdapter .

Definiowanie plików XML

Przede wszystkim wejdź do folderu do rysowania i utwórz 4 różne kształty:

  • shape_top

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp"/>

  • shape_normal

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp"/>

  • shape_bottom

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:bottomRightRadius="10dp"
        android:bottomRightRadius="10dp"/>

  • kształt_ zaokrąglony

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp"
        android:bottomRightRadius="10dp"
        android:bottomRightRadius="10dp"/>

Teraz utwórz inny układ wierszy dla każdego kształtu, np. Dla shape_top:

  • Możesz również zrobić to programowo zmieniając tło.

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="10dp"
        android:fontFamily="sans-serif-light"
        android:text="TextView"
        android:textSize="22dp" />
    
    <TextView
        android:id="@+id/txtValue1"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:textSize="22dp"
        android:layout_gravity="right|center"
        android:gravity="center|right"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="35dp"
        android:text="Fix"
        android:scaleType="fitEnd" />

I zdefiniuj selektor dla każdej listy kształtów, tj. Dla shape_top:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Selected Item -->

    <item android:state_selected="true"
        android:drawable="@drawable/shape_top" />
    <item android:state_activated="true"
        android:drawable="@drawable/shape_top" />

    <!-- Default Item -->
    <item android:state_selected="false"
        android:drawable="@android:color/transparent" />
</selector>

Zmień CustomAdapter

Na koniec zdefiniuj opcje układu w CustomAdapter:

if(position==0)
{
 convertView = mInflater.inflate(R.layout.list_layout_top, null);
}
else
{
 convertView = mInflater.inflate(R.layout.list_layout_normal, null);
}

if(position==getCount()-1)
{
convertView = mInflater.inflate(R.layout.list_layout_bottom, null);
}

if(getCount()==1)
{
convertView = mInflater.inflate(R.layout.list_layout_unique, null);
}

I gotowe!

Machado
źródło
1

aby zrobić obramowanie, musisz utworzyć inny plik xml z właściwością bryły i rogów w folderze do rysowania i wywołać go w tle

pawan kumar
źródło
0

Używam widoku niestandardowego, który układam na innych i który po prostu rysuje 4 małe rogi w tym samym kolorze co tło. Działa to niezależnie od zawartości widoku i nie zajmuje dużo pamięci.

public class RoundedCornersView extends View {
    private float mRadius;
    private int mColor = Color.WHITE;
    private Paint mPaint;
    private Path mPath;

    public RoundedCornersView(Context context) {
        super(context);
        init();
    }

    public RoundedCornersView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();

        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.RoundedCornersView,
                0, 0);

        try {
            setRadius(a.getDimension(R.styleable.RoundedCornersView_radius, 0));
            setColor(a.getColor(R.styleable.RoundedCornersView_cornersColor, Color.WHITE));
        } finally {
            a.recycle();
        }
    }

    private void init() {
        setColor(mColor);
        setRadius(mRadius);
    }

    private void setColor(int color) {
        mColor = color;
        mPaint = new Paint();
        mPaint.setColor(mColor);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);

        invalidate();
    }

    private void setRadius(float radius) {
        mRadius = radius;
        RectF r = new RectF(0, 0, 2 * mRadius, 2 * mRadius);
        mPath = new Path();
        mPath.moveTo(0,0);
        mPath.lineTo(0, mRadius);
        mPath.arcTo(r, 180, 90);
        mPath.lineTo(0,0);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        /*Paint paint = new Paint();
        paint.setColor(Color.RED);
        canvas.drawRect(0, 0, mRadius, mRadius, paint);*/

        int w = getWidth();
        int h = getHeight();
        canvas.drawPath(mPath, mPaint);
        canvas.save();
        canvas.translate(w, 0);
        canvas.rotate(90);
        canvas.drawPath(mPath, mPaint);
        canvas.restore();
        canvas.save();
        canvas.translate(w, h);
        canvas.rotate(180);
        canvas.drawPath(mPath, mPaint);
        canvas.restore();
        canvas.translate(0, h);
        canvas.rotate(270);
        canvas.drawPath(mPath, mPaint);
    }
}
mbonnin
źródło