Jak zrobić ImageView z zaokrąglonymi narożnikami?

573

W Androidzie ImageView jest domyślnie prostokątem. Jak mogę zrobić z niego zaokrąglony prostokąt (odciąć wszystkie 4 rogi mojej mapy bitowej, aby były zaokrąglonymi prostokątami) w ImageView?

Michał
źródło
Może to być pomocne stackoverflow.com/questions/26850780/…
Mangesh
Ukryta poniżej starszych, bardziej skomplikowanych odpowiedzi jest, co moim zdaniem, powinna być teraz akceptowaną odpowiedzią: RoundedBitmapDrawable , dodana w wersji 21 biblioteki wsparcia v4
Jonik
Możesz to zrobić najłatwiej, używając CardView z ImageView wewnątrz - spójrz na przykład stackoverflow.com/a/41479670/4516797
Taras Vovkovych
Ta biblioteka jest bardzo przydatna.
grrigore,
Sprawdź to teraz, musimy ShapeableImageViewzrobić okrągły lub okrągły obraz Zobacz stackoverflow.com/a/61086632/7666442
Nilesh Rathod

Odpowiedzi:

544

To dość późno, ale dla każdego, kto tego szuka, możesz wykonać następujący kod, aby ręcznie zaokrąglić rogi zdjęć.

http://www.ruibm.com/?p=184

To nie jest mój kod, ale go użyłem i działa wspaniale. Użyłem go jako pomocnika w klasie ImageHelper i rozszerzyłem go nieco, aby uzyskać ilość wtapiania potrzebną dla danego obrazu.

Ostateczny kod wygląda następująco:

package com.company.app.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;

public class ImageHelper {
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                .getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = pixels;

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        return output;
    }
}

Mam nadzieję, że to komuś pomoże!

George Walters II
źródło
4
Nie działa na wszystkich urządzeniach.Czy potrzebuję zmiany w dowolnym miejscu?
Spring Breaker
7
To zajmuje prawie 0,03 sekundy, aby zrobić to dla obrazu 200 * 200, więc myślę, że nie jest to najlepsze rozwiązanie.
Jacky,
2
Zaokrągla tylko górny lewy i prawy górny róg. Dlaczego ?
Prateek
1
@ Rozwiązanie vinc3m1 tutaj github.com/makeramen/RoundedImageView działa naprawdę dobrze! zobacz także jego odpowiedź ( stackoverflow.com/a/15032283/2048266 )
nommer
16
Nie działa dobrze, gdy próbujesz ustawić typ widoku obrazu, działa tylko fitXY, centerCrop i inni wykazują nieprzewidywalne wyniki, czy ktoś tutaj ma te same problemy?
Shivansh,
211

Podczas gdy powyższa odpowiedź działa, Romain Guy (główny programista Androida) pokazuje lepszą metodę na swoim blogu, która zużywa mniej pamięci, używając modułu cieniującego, który nie tworzy kopii mapy bitowej. Ogólny zarys funkcjonalności znajduje się tutaj:

BitmapShader shader;
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);

RectF rect = new RectF(0.0f, 0.0f, width, height);

// rect contains the bounds of the shape
// radius is the radius in pixels of the rounded corners
// paint contains the shader that will texture the shape
canvas.drawRoundRect(rect, radius, radius, paint);

Zaletą tego w porównaniu z innymi metodami jest to, że:

  • nie tworzy osobnej kopii mapy bitowej, która zużywa dużo pamięci z dużymi obrazami [w porównaniu z większością innych odpowiedzi tutaj]
  • obsługuje antyialiasing [w stosunku do metody clipPath]
  • obsługuje metodę alpha [vs xfermode + porterduff]
  • obsługuje przyspieszenie sprzętowe [vs metoda clipPath]
  • rysuje tylko raz na kanwie [vs metody xfermode i clippath]

Utworzyłem RoundedImageView na podstawie tego kodu, który zawija tę logikę w ImageView i dodaje odpowiednią ScaleTypeobsługę oraz opcjonalną zaokrągloną ramkę.

vinc3m1
źródło
W twojej / example / res / layout / rounded_item.xml dlaczego określić src obrazu, gdy wszystkie źródła są sztywno? Ładne demo, po prostu przesada.
Ktoś gdzieś
twoja próbka ma poważny problem z brakiem pamięci, podobnie jak oryginalna próbka Romaina Guy'a. Nadal nie wiem, co go powoduje, ale tak jak jego kod, jest to bardzo trudne do znalezienia. Jeśli nie widzisz awarii aplikacji z powodu OOM, możesz obracać aplikację wiele razy, aż do jej wystąpienia (zależy od urządzenia, pamięci ROM itp.). Mówiłem o tym w przeszłości tutaj: stackoverflow.com/questions/14109187/…
programista Androida
1
Nikt inny nie zgłasza problemu braku pamięci, więc musi to być coś, co robisz poza kodem, co jest niepoprawne. Przykład poprawnie przechowuje ograniczony zestaw bitmap w adapterze bez ponownego ich tworzenia przy każdym rysowaniu widoku. Przykład pokazany tutaj to fragment metody draw () w Drawable, która wykorzystuje odniesienie do oryginalnej mapy bitowej, którą przechowuje i działa poprawnie. To jest nie oznaczało zmianę oryginalnej bitmapy, ale tylko czynią go z zaokrąglonymi narożnikami. Centralne kadrowanie działa również dobrze w tym przykładzie.
vinc3m1
1
Jeśli możesz dostarczyć zrzuty ekranu lub urządzenia, na których to nie działa, lub nawet posunąć się do zaoferowania naprawy i żądania ściągnięcia, byłoby to najbardziej produktywne. Testowałem obracanie wiele razy na moich urządzeniach i pamięć pozostaje taka sama.
vinc3m1
11
Pamiętaj, że nie będzie działać, jeśli rozmiar obrazu jest większy niż 2048 pikseli. Moduł cieniujący nie obsługuje większej tekstury.
Gábor
209

Innym łatwym sposobem jest użycie CardView z promieniem narożnika i ImageView wewnątrz:

  <android.support.v7.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:cardCornerRadius="8dp"
            android:layout_margin="5dp"
            android:elevation="10dp">

            <ImageView
                android:id="@+id/roundedImageView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/image"
                android:background="@color/white"
                android:scaleType="centerCrop"
                />
        </android.support.v7.widget.CardView>

wprowadź opis zdjęcia tutaj

Taras Vovkovych
źródło
5
Wydaje się, że to dobre obejście. Ale nie przycina zdjęć na pre-Lollipops.
Nikolai
1
Co jeśli chcemy, aby promień był tylko w lewym górnym i prawym górnym rogu, a nie we wszystkich narożnikach?
Pratik Singhal
3
Bardzo prosty i elegancki sposób na zastosowanie granicy krzywej w dowolnym widoku.
AMI CHARADAVA
1
Dobre rozwiązanie, ale podniesienie jest obsługiwane tylko w interfejsie API na poziomie 21 i wyższym
Saad Bilal
1
Aby wyłączyć podniesienie karty, użyj aplikacji: cardElevation = "0dp" (nie android: podwyższenie)
Johnny Five
148

Przycinanie do zaokrąglonych kształtów zostało dodane do Viewklasy w API 21.

Po prostu zrób to:

  • Utwórz zaokrąglony kształt do rysowania, coś takiego:

res / drawable / round_outline.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="10dp" />
    ...
</shape>
  • Ustaw drawable jako tło ImageView: android:background="@drawable/round_outline"
  • Zgodnie z tą dokumentacją wszystko, co musisz zrobić, to dodaćandroid:clipToOutline="true"

Niestety wystąpił błąd i ten atrybut XML nie został rozpoznany. Na szczęście nadal możemy ustawić przycinanie w Javie:

  • W Twojej działalności lub fragmencie: ImageView.setClipToOutline(true)

Oto jak to będzie wyglądać:

wprowadź opis zdjęcia tutaj

Uwaga:

Ta metoda działa na dowolnym kształcie do rysowania (nie tylko zaokrąglonym). Spowoduje to przycięcie ImageView do dowolnego kształtu kształtu zdefiniowanego w Drawable xml.

Specjalna uwaga na temat ImageViews

setClipToOutline()działa tylko wtedy, gdy tło Widoku jest ustawione na kształt, który można rysować. Jeśli ten kształt tła istnieje, widok traktuje kontur kształtu jako obramowanie do celów wycinania i cieniowania.

Oznacza to, że jeśli chcesz użyć setClipToOutline()do zaokrąglania rogów w ImageView, obraz należy ustawić za pomocą android:srczamiast android:background(ponieważ tło musi być ustawione na zaokrąglony kształt). Jeśli MUSISZ użyć tła do ustawienia obrazu zamiast src, możesz użyć tego obejścia:

  • Utwórz układ i ustaw jego tło na swój kształt
  • Zawiń ten układ wokół ImageView (bez wypełnienia)
  • ImageView (włączając wszystko inne w układzie) będzie teraz wyświetlał się z zaokrąglonym kształtem układu.
głodny głód
źródło
10
Błąd: (x) Nie znaleziono identyfikatora zasobu dla atrybutu „clipToOutline” w pakiecie „android”
Anu Martin,
7
Zamiast tego android:clipToOutlinenależy użyć android:outlineProvider="background".
WindRider
2
Innym powodem, dla którego tak bardzo „uwielbiam” Google, jest to, że ten błąd jest prawie w moim wieku i nadal mieszka w jego małym świecie. Google wydaje się nie dawać cr * apu w tej sprawie))
Farid
1
Wydaje mi się, że nie powiodło się z tą metodą, gdy ustawiłem tylko górny lewy i górny prawy narożnik w kształcie tła na zaokrąglone.
Peterdk
@AnuMartin to znany problem - issueetracker.google.com/issues/37036728
Vadim Kotov
132

W wersji 21 biblioteki Support istnieje teraz rozwiązanie tego problemu: nazywa się RoundedBitmapDrawable .

Zasadniczo jest tak jak normalny Drawable, tyle że dajesz mu promień narożnika do przycinania za pomocą:

setCornerRadius(float cornerRadius)

Tak więc, zaczynając od Bitmap srci cel ImageView, wyglądałby mniej więcej tak:

RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(res, src);
dr.setCornerRadius(cornerRadius);
imageView.setImageDrawable(dr);
tyczj
źródło
3
Wielkie dzięki, oto następny krok: stackoverflow.com/questions/24878740/…
David d C e Freitas
tak jest, android.support.v4.graphics.drawable.RoundedBitmapDrawableFactorywięc v4też obsługuje to.
Deadfish
2
@deadfish tak jest w v4bibliotece wsparcia, ale dopiero REVISION 21w bibliotece wsparcia
tyczj
3
To rozwiązanie jest proste i aktualne. Wymaga najmniejszej ilości kodu i ma doskonałą rozszerzalność. Może pracować z obrazami z pliku lokalnego, z pamięci podręcznej, a nawet z NetworkImageView firmy Volley. Zdecydowanie zgadzam się, że powinna to być obecnie akceptowana odpowiedź, jak zauważył @Jonik.
katie
2
Niestety nie działa z scaleType centerCrop(wsparcie biblioteki v25.3.1)
rocknow
67

Zrobiłem przez Custom ImageView:

public class RoundRectCornerImageView extends ImageView {

    private float radius = 18.0f;
    private Path path;
    private RectF rect;

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

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

    public RoundRectCornerImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        path = new Path();

    }

    @Override
    protected void onDraw(Canvas canvas) {
        rect = new RectF(0, 0, this.getWidth(), this.getHeight());
        path.addRoundRect(rect, radius, radius, Path.Direction.CW);
        canvas.clipPath(path);
        super.onDraw(canvas);
    }
}

Jak używać:

<com.mypackage.RoundRectCornerImageView
     android:id="@+id/imageView"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@drawable/image"
     android:scaleType="fitXY" />

Wynik:

wprowadź opis zdjęcia tutaj

Mam nadzieję, że to ci pomoże.

Hiren Patel
źródło
powoduje to rozmycie obrazu
Amit Hooda
2
działa nawet z Androidem: scaleType = "centerCrop", prosty, nie tworzy nowej mapy bitowej. Dzięki!
ernazm
1
@Hiren To rozwiązanie działa dobrze dla ImageView z obrazem w tle. Ale to nie działa dla ImageViews, który ma tylko kolor tła i nie ma obrazu. Czy możesz mi powiedzieć, dlaczego tak się dzieje?
user2991413,
Canvas.clipPath()może powodować java.lang.UnsupportedOperationExceptionw niektórych przypadkach. Zobacz stackoverflow.com/questions/13248904/…
Artyom
1
To rozwiązanie działa tylko dla zestawu obrazów z android:background, ale nie android:src.
CoolMind,
64

Szybkie rozwiązanie xml -

<android.support.v7.widget.CardView
            android:layout_width="40dp"
            android:layout_height="40dp"
            app:cardElevation="0dp"
            app:cardCornerRadius="4dp">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/rounded_user_image"
        android:scaleType="fitXY"/>

</android.support.v7.widget.CardView>

Możesz ustawić żądaną szerokość, wysokość i promień w CardView i scaleType w ImageView.

W systemie AndroidX użyj <androidx.cardview.widget.CardView>

Chirag Mittal
źródło
4
takie podejście zadziałało w moim przypadku z androidx.cardview.widget.CardView
Ivan
7
Nie wiesz, dlaczego to nie ma więcej głosów pozytywnych? Moim zdaniem najlepsze rozwiązanie bez bibliotek i mnóstwa gównianego kodu (chociaż w moim przypadku użyłem skalowania centerCrop).
ThemBones
1
Niewiele jeszcze głosów pozytywnych, ponieważ jest to nowa odpowiedź. Ale dodałem +1, aby wkrótce go zwiększyć! Dzięki!
Micer,
jednak działa, ale tutaj obraz się rozciągnie scaleType="fitXY"i nie wygląda poprawnie @ThemBones
WIZARD
@WIZARD dlatego wspomniałem, że możesz ustawić żądaną skalęTyp na ImageView
Chirag Mittal
57

Odkryłem, że obie metody były bardzo pomocne w znalezieniu działającego rozwiązania. Oto moja wersja kompozytowa, która jest niezależna od pikseli i pozwala mieć pewne kwadratowe rogi, a reszta narożników ma ten sam promień (co jest zwykłym przypadkiem użycia). Dzięki obu powyższym rozwiązaniom:

public static Bitmap getRoundedCornerBitmap(Context context, Bitmap input, int pixels , int w , int h , boolean squareTL, boolean squareTR, boolean squareBL, boolean squareBR  ) {

    Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
    Canvas canvas = new Canvas(output);
    final float densityMultiplier = context.getResources().getDisplayMetrics().density;

    final int color = 0xff424242;
    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, w, h);
    final RectF rectF = new RectF(rect);

    //make sure that our rounded corner is scaled appropriately
    final float roundPx = pixels*densityMultiplier;

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawRoundRect(rectF, roundPx, roundPx, paint);


    //draw rectangles over the corners we want to be square
    if (squareTL ){
        canvas.drawRect(0, h/2, w/2, h, paint);
    }
    if (squareTR ){
        canvas.drawRect(w/2, h/2, w, h, paint);
    }
    if (squareBL ){
        canvas.drawRect(0, 0, w/2, h/2, paint);
    }
    if (squareBR ){
        canvas.drawRect(w/2, 0, w, h/2, paint);
    }


    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(input, 0,0, paint);

    return output;
}

Ponadto przesłoniłem ImageView, aby wstawić to, aby móc go zdefiniować w formacie xml. Możesz dodać trochę logiki, którą robi super połączenie tutaj, ale skomentowałem to, ponieważ w moim przypadku nie jest to pomocne.

    @Override
protected void onDraw(Canvas canvas) {
    //super.onDraw(canvas);
        Drawable drawable = getDrawable();

        Bitmap b =  ((BitmapDrawable)drawable).getBitmap() ;
        Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

        int w = getWidth(), h = getHeight();


        Bitmap roundBitmap =  CropImageView.getRoundedCornerBitmap( getContext(), bitmap,10 , w, h , true, false,true, false);
        canvas.drawBitmap(roundBitmap, 0,0 , null);
}

Mam nadzieję że to pomoże!

Caspar Harmer
źródło
4
całkiem niesamowite, zwłaszcza rozszerzenie ImageView
Someone Somewhere
2
Prostym sposobem na zachowanie logiki ImageView # onDraw () jest ustawienie zaokrąglonej narożnej mapy bitowej na możliwą do rysowania ImageView i pozostawienie super.onDraw (), aby narysować mapę bitową. Utworzyłem klasę RoundedCornerImageView , a jej przykład użycia znajduje się tutaj . Zauważ, że użyta metoda getRoundedCornerBitmap () nie jest niezależna od pikseli.
umbalaconmeogia
Dzięki za RoundedCornerImageView. Użyłem go, ale zmodyfikowałem, aby był niezależny od gęstości pikseli.
PacificSky
Kod źródłowy do RoundedCornerImageView firmy Umba znajduje się tutaj: code.google.com/p/android-batsg/source/browse/trunk/…
Someone Somewhere
@Caspar Harmer działa dobrze tylko 1 edycja ... są cztery warunki .. po prostu je zmień, jak gdybym ustawił wartość prawda, prawda, fałsz, fałsz ustawi dolny narożnik zamiast górnego rogu .. w przeciwnym razie kod działa dobrze. Więc squareTL i squareTR są odpowiednio warunkami dla squareBL i squareBR .. i na odwrót.
TheFlash
48

Zaokrąglony obraz Za pomocą ImageLoader tutaj

Utwórz DisplayImageOptions:

DisplayImageOptions options = new DisplayImageOptions.Builder()
    // this will make circle, pass the width of image 
    .displayer(new RoundedBitmapDisplayer(getResources().getDimensionPixelSize(R.dimen.image_dimen_menu))) 
    .cacheOnDisc(true)
    .build();

imageLoader.displayImage(url_for_image,ImageView,options);

Lub możesz użyć Picassobiblioteki z Square.

Picasso.with(mContext)
    .load(com.app.utility.Constants.BASE_URL+b.image)
    .placeholder(R.drawable.profile)
    .error(R.drawable.profile)
    .transform(new RoundedTransformation(50, 4))
    .resizeDimen(R.dimen.list_detail_image_size, R.dimen.list_detail_image_size)
    .centerCrop()
    .into(v.im_user);

można pobrać plik RoundedTransformation tutaj tutaj

shailesh
źródło
1
Brak obrazu
Amit Thaper,
3
Biblioteka Picassa jest dobra i bardzo łatwa do wdrożenia, bardzo dziękuję +1
Hitesh
3
Wydaje się jednak, że biblioteka Picassa nie przekształca obrazu „symbol zastępczy” i „błąd”, więc jeśli obraz nie ładuje się (błąd) lub ładuje się początkowo (symbol zastępczy), obraz nie będzie wyświetlany jako zaokrąglony. github.com/square/picasso/issues/337
Pelpotronic
Inne przydatne transformacje Picassa są dostarczane przez tę bibliotekę, która zawiera także RoundedCornersTransformation: github.com/wasabeef/picasso-transformations
Massimo
Nie działa z kadrowaniem zdjęć w Univ. Image Loader.
Yar
26

Ponieważ wszystkie odpowiedzi wydawały mi się zbyt skomplikowane tylko dla zaokrąglonych rogów, pomyślałem i doszedłem do innego rozwiązania, które moim zdaniem warto udostępnić, tylko z XML, na wypadek gdybyś miał trochę miejsca wokół obrazu:

Utwórz obramowany kształt z przezroczystą treścią:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners 
        android:radius="30dp" />
    <stroke 
        android:color="#ffffffff"
        android:width="10dp" />
</shape> 

Następnie w RelativeLayout możesz najpierw umieścić obraz, a następnie w tym samym miejscu nad kształtem za pomocą innego ImageView. Kształt okładki powinien być większy o wielkość szerokości obramowania. Zachowaj ostrożność, aby wziąć większy promień narożnika, ponieważ promień zewnętrzny jest zdefiniowany, ale promień wewnętrzny obejmuje obraz.

Mam nadzieję, że to też komuś pomoże.

Edytuj zgodnie z żądaniem CQM przykładowy układ względny:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/imageToShow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/imgCorners"
        android:layout_alignLeft="@+id/imgCorners"
        android:layout_alignRight="@+id/imgCorners"
        android:layout_alignTop="@+id/imgCorners"
        android:background="#ffffff"
        android:contentDescription="@string/desc"
        android:padding="5dp"
        android:scaleType="centerCrop" />

    <ImageView
        android:id="@+id/imgCorners"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:contentDescription="@string/desc"
        android:src="@drawable/corners_white" />

</RelativeLayout>
chrześcijanin
źródło
czy możesz rozwinąć tę kwestię z większą ilością kodu, zwłaszcza co dzieje się z drugim widokiem obrazu i gdzie stosuje się xml „kształt z obramowaniem” (jako src lub jako tło?) kilka pytań tutaj. Chcę polubić to rozwiązanie, ponieważ pozwoli mi ono kontrolować wszystkie cztery zakręty niezależnie
CQM
1
Chociaż wydaje się być prostą odpowiedzią, niestety dodaje margines wokół „zamaskowanego” widoku obrazu, co jest niepożądanym efektem ubocznym.
Abdalrahman Shatou
tak, ale to samo działa z ImageView opartym na rysunku PNG z zaokrąglonymi narożnikami i przezroczystym tłem lub 9-patch-Drawable, jeśli masz nieokreślony aspekt.
Christian
Robię to samo i działa; po prostu chcesz wiedzieć, czy nie spowoduje to problemów z orientacją i innym rozmiarem telefonu?
otwarte i bezpłatne
Utrzymanie wymiarów względem siebie nie powinno stanowić problemu.
Christian
22

Począwszy od wersji 1.2.0-alpha03z tym Components Library Materiał nie jest nowy ShapeableImageView.

Możesz użyć czegoś takiego jak:

  <com.google.android.material.imageview.ShapeableImageView
      ...
      app:shapeAppearanceOverlay="@style/roundedImageView"
      app:srcCompat="@drawable/ic_image" />

z:

  <style name="roundedImageView" parent="">
    <item name="cornerFamily">rounded</item>
    <item name="cornerSize">8dp</item>
  </style>

Lub programowo:

float radius = getResources().getDimension(R.dimen.default_corner_radius);
imageView.setShapeAppearanceModel(imageView.getShapeAppearanceModel()
    .toBuilder()
    .setAllCorners(CornerFamily.ROUNDED,radius)
    .build());

wprowadź opis zdjęcia tutaj

Gabriele Mariotti
źródło
Jeśli obraz ma kolor tła, powoduje to obecnie wyświetlenie koloru tła, który pojawia się pod zaokrąglonymi narożnikami. To również ignoruje właściwość scaleType na obrazie.
inokey
14

Moja implementacja ImageView z widżetem o zaokrąglonych rogach, który (w dół || w górę) dostosowuje rozmiar obrazu do wymaganych wymiarów. Wykorzystuje kod z CaspNZ.

public class ImageViewRounded extends ImageView {

    public ImageViewRounded(Context context) {
        super(context);
    }

    public ImageViewRounded(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        BitmapDrawable drawable = (BitmapDrawable) getDrawable();

        if (drawable == null) {
            return;
        }

        if (getWidth() == 0 || getHeight() == 0) {
            return; 
        }

        Bitmap fullSizeBitmap = drawable.getBitmap();

        int scaledWidth = getMeasuredWidth();
        int scaledHeight = getMeasuredHeight();

        Bitmap mScaledBitmap;
        if (scaledWidth == fullSizeBitmap.getWidth() && scaledHeight == fullSizeBitmap.getHeight()) {
            mScaledBitmap = fullSizeBitmap;
        } else {
            mScaledBitmap = Bitmap.createScaledBitmap(fullSizeBitmap, scaledWidth, scaledHeight, true /* filter */);
        }

        Bitmap roundBitmap = ImageUtilities.getRoundedCornerBitmap(getContext(), mScaledBitmap, 5, scaledWidth, scaledHeight,
                false, false, false, false);
        canvas.drawBitmap(roundBitmap, 0, 0, null);

    }

}
Damjan
źródło
12
Skąd pochodzi ImageUtilities?
JasonWyatt,
1
@JasonWyatt patrz poniżej post Sorrodos
Damjan
12

Od niedawna istnieje inny sposób - użycie generowanego API Glide . Zajmuje to trochę początkowej pracy, ale daje całą moc Glide z elastycznością do robienia czegokolwiek, ponieważ piszesz rzeczywisty kod, więc myślę, że jest to dobre rozwiązanie na dłuższą metę. Ponadto użycie jest bardzo proste i schludne.

Najpierw skonfiguruj wersję Glide 4+:

implementation 'com.github.bumptech.glide:glide:4.6.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'

Następnie utwórz klasę modułu aplikacji Glid, aby uruchomić przetwarzanie adnotacji:

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}

Następnie utwórz rozszerzenie Glide, które faktycznie działa. Możesz go dostosować, aby robić, co chcesz:

@GlideExtension
public class MyGlideExtension {

    private MyGlideExtension() {}

    @NonNull
    @GlideOption
    public static RequestOptions roundedCorners(RequestOptions options, @NonNull Context context, int cornerRadius) {
        int px = Math.round(cornerRadius * (context.getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));
        return options.transforms(new RoundedCorners(px));
    }
}

Po dodaniu tych plików skompiluj projekt.

Następnie użyj go w swoim kodzie w następujący sposób:

GlideApp.with(this)
        .load(imageUrl)
        .roundedCorners(getApplicationContext(), 5)
        .into(imageView);
Sir Codesalot
źródło
Nie zapomnij dodać spacji między parametrami RequestOptionsiw optionsparams
StevenTB,
Gotowy. Dzięki za wkład.
Sir Codesalot,
.roundedCorners nie nadchodzi, czy musimy skonfigurować coś jeszcze? Nawet po przebudowie projektu
dr aNdRO,
To zadziałało dla mnie, dziękuję. Uznałem, że łatwiej jest uniknąć korzystania z @GlideExtensionklasy z adnotacjami i po prostu poszedłem .transform(new RoundedCorners(px))tam, gdzie pxjest to samo ( int px = Math.round(cornerRadius * (context.getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT));).
Michael Osofsky,
10

Jest fajna biblioteka, która pozwala kształtować obrazy.

Oto przykład:

<com.github.siyamed.shapeimageview.mask.PorterShapeImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:siShape="@drawable/shape_rounded_rectangle"
    android:src="@drawable/neo"
    app:siSquare="true"/>

Definicja kształtu:

<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
    <corners
        android:topLeftRadius="18dp"
        android:topRightRadius="18dp"
        android:bottomLeftRadius="18dp"
        android:bottomRightRadius="18dp" />
    <solid android:color="@color/black" />
</shape>

Wynik:

wynik

Grrigore
źródło
1
To jest świetne i robi o wiele więcej, jakbyś mógł dodać obramowanie i użyć dowolnego kształtu
Adam Kis
8

Oto prosty przykład przesłaniający imageView, którego możesz użyć w projektancie układu do podglądu.

public class RoundedImageView extends ImageView {

    public RoundedImageView(Context context) {
        super(context);
    }

    public RoundedImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        float radius = 0.1f;
        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
        RoundedBitmapDrawable rid = RoundedBitmapDrawableFactory.create(getResources(), bitmap);
        rid.setCornerRadius(bitmap.getWidth() * radius);
        super.setImageDrawable(rid);
    }
}

To jest szybkie rozwiązanie. Promień jest stosowany we wszystkich narożnikach i jest oparty na procentowej szerokości mapy bitowej.

Właśnie zastąpiłem setImageDrawablei użyłem metody wsparcia v4 dla zaokrąglonej mapy bitowej rysowanej.

Stosowanie:

<com.example.widgets.RoundedImageView
        android:layout_width="39dp"
        android:layout_height="39dp"
        android:src="@drawable/your_drawable" />

Podgląd za pomocą imageView i niestandardowego imageView:

wprowadź opis zdjęcia tutaj

martwa ryba
źródło
Działa to w każdej sytuacji, dziękuję. Uratowałeś mi dzień.
Mehul Solanki,
7

Powinieneś rozciągnąć ImageViewi narysować własny zaokrąglony prostokąt.

Jeśli chcesz umieścić ramkę wokół obrazu, możesz również nałożyć zaokrągloną ramkę na widok obrazu w układzie.

[edytuj] Nakładaj ramkę na oryginalny obraz, FrameLayoutna przykład za pomocą . Pierwszym elementem FrameLayoutbędzie zaokrąglony obraz, który chcesz wyświetlić. Następnie dodaj kolejną ImageViewz ramką. Drugi ImageViewzostanie wyświetlony na górze oryginału, ImageViewa zatem Android narysuje jego zawartość nad oryginałem ImageView.

MrSnowflake
źródło
Dziękuję Ci. Ale istnieje tylko metoda setDrawable dla ImageView, w jaki sposób mogę ustawićDrawable ImageView do zawartości mojego obrazu, a następnie nałożyć zaokrągloną ramkę na ImageView?
Michael
Przepraszam, byłem niejasny. Miałem na myśli nałożenie się na układ: w ten sposób (tj.) Skorzystaj z funkcji FrameLayoutput a ImageViewi dodaj kolejną ImageViewz zaokrągloną ramką. W ten sposób pierwszy ImageViewwyświetli wybrane zdjęcie, a drugi ImageFramewyświetli zaokrągloną ramkę.
MrSnowflake
Prawidłowo - z FrameLayout możesz nakładać jedno zdjęcie / widok na inny. Możesz także skorzystać z tagu android: foreground FrameLayout.
Richard Le Mesurier
7

Romain Guy jest tam, gdzie jest.

Wersja skrócona w następujący sposób.

Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.image)).getBitmap();

Bitmap bitmapRounded = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
Canvas canvas = new Canvas(bitmapRounded);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
canvas.drawRoundRect((new RectF(0.0f, 0.0f, bitmap.getWidth(), bitmap.getHeight())), 10, 10, paint);

imageView.setImageBitmap(bitmapRounded);
Alex
źródło
niestety, mimo że działa, ale podobnie jak pozostałe rozwiązania tutaj, tworzy nową bitmapę zamiast używać obecnej.
programista Androida
nie całkiem. bitmapRounded będzie używany wielokrotnie. jeśli miałeś dostęp do rysowalnego obszaru roboczego, możesz użyć metody rysowania bezpośrednio zamiast generowania nowej mapy bitowej.
Alex
jak to robisz załóżmy, że nie używam żadnej specjalnej rysowalnej i obsługuję tylko jedną bitmapę i używam setImageBitmap na końcu procesu. jak miałbym to osiągnąć?
programista Androida
sprawdź przykład Romaina guy ciekawy-creature.org/2012/12/11/... i przykładową aplikację docs.google.com/file/d/0B3dxhm5xm1sia2NfM3VKTXNjUnc/edit
Alex
oba nie zmieniają mapy bitowej, ale zawijają ją za pomocą niestandardowego rysunku i niestandardowego widoku obrazu. nie o to pytałem. zapytałem, jak zmienić samą mapę bitową.
programista Androida
7

To czyste rozwiązanie XML było wystarczająco dobre w moim przypadku. http://www.techrepublic.com/article/pro-tip-round-corners-on-an-android-imageview-with-this-hack/

EDYTOWAĆ

Oto odpowiedź w skrócie:

W folderze / res / drawable utwórz plik frame.xml. W nim definiujemy prosty prostokąt z zaokrąglonymi narożnikami i przezroczystym środkiem.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
     <solid android:color="#00ffffff" />
     <padding android:left="6dp"
        android:top="6dp"
        android:right="6dp"
        android:bottom="6dp" />
     <corners android:radius="12dp" />
     <stroke android:width="6dp" android:color="#ffffffff" />
</shape>

W pliku układu dodajesz LinearLayout, który zawiera standardowy ImageView, a także zagnieżdżony FrameLayout. FrameLayout korzysta z wypełnienia i niestandardowej szuflady, aby dać złudzenie zaokrąglonych rogów.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_gravity="center"
    android:gravity="center" 
    android:background="#ffffffff">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="6dp"
        android:src="@drawable/tr"/>

    <FrameLayout 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="6dp"
            android:src="@drawable/tr"/>

        <ImageView 
             android:src="@drawable/frame"
             android:layout_width="match_parent"
             android:layout_height="match_parent" />

    </FrameLayout>

</LinearLayout>
j7nn7k
źródło
fajny pomysł, użyłem go do pokazania nierównomiernych rogów ImageView
Gal Rom
6

Podpierając się do George'a Waltersa II powyżej, właśnie wziąłem jego odpowiedź i nieco ją rozszerzyłem, aby w inny sposób obsługiwać zaokrąglanie poszczególnych rogów. Można to nieco zoptymalizować (niektóre docelowe rektyki się pokrywają), ale nie za dużo.

Wiem, że ten wątek jest nieco stary, ale jest to jeden z najlepszych wyników w zapytaniach w Google na temat zaokrąglania rogów ImageViews na Androida.

/**
 * Use this method to scale a bitmap and give it specific rounded corners.
 * @param context Context object used to ascertain display density.
 * @param bitmap The original bitmap that will be scaled and have rounded corners applied to it.
 * @param upperLeft Corner radius for upper left.
 * @param upperRight Corner radius for upper right.
 * @param lowerRight Corner radius for lower right.
 * @param lowerLeft Corner radius for lower left.
 * @param endWidth Width to which to scale original bitmap.
 * @param endHeight Height to which to scale original bitmap.
 * @return Scaled bitmap with rounded corners.
 */
public static Bitmap getRoundedCornerBitmap(Context context, Bitmap bitmap, float upperLeft,
        float upperRight, float lowerRight, float lowerLeft, int endWidth,
        int endHeight) {
    float densityMultiplier = context.getResources().getDisplayMetrics().density;

    // scale incoming bitmap to appropriate px size given arguments and display dpi
    bitmap = Bitmap.createScaledBitmap(bitmap, 
            Math.round(endWidth * densityMultiplier),
            Math.round(endHeight * densityMultiplier), true);

    // create empty bitmap for drawing
    Bitmap output = Bitmap.createBitmap(
            Math.round(endWidth * densityMultiplier),
            Math.round(endHeight * densityMultiplier), Config.ARGB_8888);

    // get canvas for empty bitmap
    Canvas canvas = new Canvas(output);
    int width = canvas.getWidth();
    int height = canvas.getHeight();

    // scale the rounded corners appropriately given dpi
    upperLeft *= densityMultiplier;
    upperRight *= densityMultiplier;
    lowerRight *= densityMultiplier;
    lowerLeft *= densityMultiplier;

    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setColor(Color.WHITE);

    // fill the canvas with transparency
    canvas.drawARGB(0, 0, 0, 0);

    // draw the rounded corners around the image rect. clockwise, starting in upper left.
    canvas.drawCircle(upperLeft, upperLeft, upperLeft, paint);
    canvas.drawCircle(width - upperRight, upperRight, upperRight, paint);
    canvas.drawCircle(width - lowerRight, height - lowerRight, lowerRight, paint);
    canvas.drawCircle(lowerLeft, height - lowerLeft, lowerLeft, paint);

    // fill in all the gaps between circles. clockwise, starting at top.
    RectF rectT = new RectF(upperLeft, 0, width - upperRight, height / 2);
    RectF rectR = new RectF(width / 2, upperRight, width, height - lowerRight);
    RectF rectB = new RectF(lowerLeft, height / 2, width - lowerRight, height);
    RectF rectL = new RectF(0, upperLeft, width / 2, height - lowerLeft);

    canvas.drawRect(rectT, paint);
    canvas.drawRect(rectR, paint);
    canvas.drawRect(rectB, paint);
    canvas.drawRect(rectL, paint);

    // set up the rect for the image
    Rect imageRect = new Rect(0, 0, width, height);

    // set up paint object such that it only paints on Color.WHITE
    paint.setXfermode(new AvoidXfermode(Color.WHITE, 255, AvoidXfermode.Mode.TARGET));

    // draw resized bitmap onto imageRect in canvas, using paint as configured above
    canvas.drawBitmap(bitmap, imageRect, imageRect, paint);

    return output;
}
sorrodos
źródło
+1 za dodanie mnożnika gęstości i dodanie obsługi indywidualnie zaokrąglanych rogów. Właściwie użyłem rozwiązania u góry, ponieważ twoje rozwiązanie nie całkiem działało - ale było bardzo pomocne! Zobacz moje złożone rozwiązanie poniżej:
Caspar Harmer,
6

Zastosuj kształt do swojego, imageViewjak poniżej:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <solid android:color="#faf5e6" />
    <stroke
        android:width="1dp"
        android:color="#808080" />
    <corners android:radius="15dp" />
    <padding
        android:bottom="5dp"
        android:left="5dp"
        android:right="5dp"
        android:top="5dp" />
</shape>

może ci pomóc przyjacielu.

dżigar
źródło
6

Dlaczego nie przyciąć draw()?

Oto moje rozwiązanie:

  • Rozszerz RelativeLayout z obcinaniem
  • Umieść ImageView (lub inne widoki) w układzie:

Kod:

public class RoundRelativeLayout extends RelativeLayout {

    private final float radius;

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

        TypedArray attrArray = context.obtainStyledAttributes(attrs,
                R.styleable.RoundRelativeLayout);
        radius = attrArray.getDimension(
                R.styleable.RoundRelativeLayout_radius, 0);
    }

    private boolean isPathValid;
    private final Path path = new Path();

    private Path getRoundRectPath() {
        if (isPathValid) {
            return path;
        }

        path.reset();

        int width = getWidth();
        int height = getHeight();
        RectF bounds = new RectF(0, 0, width, height);

        path.addRoundRect(bounds, radius, radius, Direction.CCW);
        isPathValid = true;
        return path;
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.clipPath(getRoundRectPath());
        super.dispatchDraw(canvas);
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.clipPath(getRoundRectPath());
        super.draw(canvas);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int oldWidth = getMeasuredWidth();
        int oldHeight = getMeasuredHeight();
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int newWidth = getMeasuredWidth();
        int newHeight = getMeasuredHeight();
        if (newWidth != oldWidth || newHeight != oldHeight) {
            isPathValid = false;
        }
    }

}
fishautumn
źródło
1
Lubię to podejście. Użyłem go do stworzenia własnego RoundImageView. Dzięki za to.
Pascal
To nie działa przy włączonym trudnym przyspieszaniu, prawda? Nie widziałem łatwego obejścia ...
secureboot
Czy możesz pokazać, jak to zrobić, mając wynik jako możliwy do rysowania, mieć możliwość dodania konturu (obrysu AKA) wokół zawartości, a także mieć możliwość wykonania tylko niektórych rogów do zaokrąglenia?
programista Androida
5

Poniżej utworzono obiekt układu zaokrąglonego prostokąta, który rysuje zaokrąglony prostokąt wokół wszystkich umieszczonych w nim obiektów potomnych. Pokazuje także, jak programowo tworzyć widoki i układy bez użycia plików xml układu.

package android.example;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MessageScreen extends Activity {
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  int mainBackgroundColor = Color.parseColor("#2E8B57");
  int labelTextColor = Color.parseColor("#FF4500");
  int messageBackgroundColor = Color.parseColor("#3300FF");
  int messageTextColor = Color.parseColor("#FFFF00");

  DisplayMetrics metrics = new DisplayMetrics();
  getWindowManager().getDefaultDisplay().getMetrics(metrics);
  float density = metrics.density;
  int minMarginSize = Math.round(density * 8);
  int paddingSize = minMarginSize * 2;
  int maxMarginSize = minMarginSize * 4;

  TextView label = new TextView(this);
  /*
   * The LayoutParams are instructions to the Layout that will contain the
   * View for laying out the View, so you need to use the LayoutParams of
   * the Layout that will contain the View.
   */
  LinearLayout.LayoutParams labelLayoutParams = new LinearLayout.LayoutParams(
    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
  label.setLayoutParams(labelLayoutParams);
  label.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
  label.setPadding(paddingSize, paddingSize, paddingSize, paddingSize);
  label.setText(R.string.title);
  label.setTextColor(labelTextColor);

  TextView message = new TextView(this);
  RoundedRectangle.LayoutParams messageLayoutParams = new RoundedRectangle.LayoutParams(
 LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
  /*
   * This is one of the calls must made to force a ViewGroup to call its
   * draw method instead of just calling the draw method of its children.
   * This tells the RoundedRectangle to put some extra space around the
   * View.
   */
  messageLayoutParams.setMargins(minMarginSize, paddingSize,
    minMarginSize, maxMarginSize);
  message.setLayoutParams(messageLayoutParams);
  message.setTextSize(TypedValue.COMPLEX_UNIT_SP, paddingSize);
  message.setText(R.string.message);
  message.setTextColor(messageTextColor);
  message.setBackgroundColor(messageBackgroundColor);

  RoundedRectangle messageContainer = new RoundedRectangle(this);
  LinearLayout.LayoutParams messageContainerLayoutParams = new LinearLayout.LayoutParams(
    LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
  messageContainerLayoutParams.setMargins(paddingSize, 0, paddingSize, 0);
  messageContainer.setLayoutParams(messageContainerLayoutParams);
  messageContainer.setOrientation(LinearLayout.VERTICAL);
  /*
   * This is one of the calls must made to force a ViewGroup to call its
   * draw method instead of just calling the draw method of its children.
   * This tells the RoundedRectangle to color the the exta space that was
   * put around the View as well as the View. This is exterior color of
   * the RoundedRectangle.
   */
  messageContainer.setBackgroundColor(mainBackgroundColor);
  /*
   * This is one of the calls must made to force a ViewGroup to call its
   * draw method instead of just calling the draw method of its children.
   * This is the interior color of the RoundedRectangle. It must be
   * different than the exterior color of the RoundedRectangle or the
   * RoundedRectangle will not call its draw method.
   */
  messageContainer.setInteriorColor(messageBackgroundColor);
  // Add the message to the RoundedRectangle.
  messageContainer.addView(message);

  //
  LinearLayout main = new LinearLayout(this);
  LinearLayout.LayoutParams mainLayoutParams = new LinearLayout.LayoutParams(
    LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
  main.setLayoutParams(mainLayoutParams);
  main.setOrientation(LinearLayout.VERTICAL);
  main.setBackgroundColor(mainBackgroundColor);
  main.addView(label);
  main.addView(messageContainer);

  setContentView(main);
 }
}

Klasa obiektu układu RoundedRectangle jest zdefiniowana tutaj:

/**
 *  A LinearLayout that draws a rounded rectangle around the child View that was added to it.
 */
package android.example;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.LinearLayout;

/**
 * A LinearLayout that has rounded corners instead of square corners.
 * 
 * @author Danny Remington
 * 
 * @see LinearLayout
 * 
 */
public class RoundedRectangle extends LinearLayout {
 private int mInteriorColor;

 public RoundedRectangle(Context p_context) {
  super(p_context);
 }

 public RoundedRectangle(Context p_context, AttributeSet attributeSet) {
  super(p_context, attributeSet);
 }

 // Listener for the onDraw event that occurs when the Layout is drawn.
 protected void onDraw(Canvas canvas) {
  Rect rect = new Rect(0, 0, getWidth(), getHeight());
  RectF rectF = new RectF(rect);
  DisplayMetrics metrics = new DisplayMetrics();
  Activity activity = (Activity) getContext();
  activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
  float density = metrics.density;
  int arcSize = Math.round(density * 10);

  Paint paint = new Paint();
  paint.setColor(mInteriorColor);

  canvas.drawRoundRect(rectF, arcSize, arcSize, paint);
 }

 /**
  * Set the background color to use inside the RoundedRectangle.
  * 
  * @param Primitive int - The color inside the rounded rectangle.
  */
 public void setInteriorColor(int interiorColor) {
  mInteriorColor = interiorColor;
 }

 /**
  * Get the background color used inside the RoundedRectangle.
  * 
  * @return Primitive int - The color inside the rounded rectangle.
  */
 public int getInteriorColor() {
  return mInteriorColor;
 }

}
Danny Remington - OMS
źródło
5

Kotlin

import android.graphics.BitmapFactory
import android.os.Bundle
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory
import kotlinx.android.synthetic.main.activity_main.*

val bitmap = BitmapFactory.decodeResource(resources, R.drawable.myImage)
val rounded = RoundedBitmapDrawableFactory.create(resources, bitmap)
rounded.cornerRadius = 20f
profileImageView.setImageDrawable(rounded)

Aby utworzyć ImageViewCircular, możemy zmienić za cornerRadiuspomocą:

rounded.isCircular = true
Vahid
źródło
4

Wielkie dzięki za pierwszą odpowiedź. Oto zmodyfikowana wersja do konwersji obrazu prostokątnego na kwadratowy (i zaokrąglony), a kolor wypełnienia jest przekazywany jako parametr.

public static Bitmap getRoundedBitmap(Bitmap bitmap, int pixels, int color) {

    Bitmap inpBitmap = bitmap;
    int width = 0;
    int height = 0;
    width = inpBitmap.getWidth();
    height = inpBitmap.getHeight();

    if (width <= height) {
        height = width;
    } else {
        width = height;
    }

    Bitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, width, height);
    final RectF rectF = new RectF(rect);
    final float roundPx = pixels;

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(inpBitmap, rect, rect, paint);

    return output;
}
mkm
źródło
4

Jeśli korzystasz z Glide Library, byłoby to pomocne:

Glide.with(getApplicationContext())
     .load(image_url)
     .asBitmap()
     .centerCrop()
     .into(new BitmapImageViewTarget(imageView) {
        @Override
        protected void setResource(Bitmap resource) {
          RoundedBitmapDrawable circularBitmapDrawable =
                       RoundedBitmapDrawableFactory.create(getApplicationContext().getResources(), resource);
          circularBitmapDrawable.setCornerRadius(dpToPx(10));
          circularBitmapDrawable.setAntiAlias(true);
          imageView.setImageDrawable(circularBitmapDrawable);
        }
     });


public int dpToPx(int dp) {
  DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics();
  return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}
Anirudh
źródło
Jeśli używasz Glide w wersji 4 i wyższej, użyj --- RequestOptions requestOptions = new RequestOptions (); requestOptions = requestOptions.transforms (new CenterCrop (), new RoundedCorners (16)); Glide.with (itemView.getContext ()) .load (item.getImage ()) .apply (requestOptions) .into (mProgramThumbnail);
B.shruti
3

jeśli twój obraz jest w Internecie, najlepszym sposobem jest użycie poślizgu i RoundedBitmapDrawableFactory(z API 21 - ale dostępny w bibliotece pomocy) w następujący sposób:

 Glide.with(ctx).load(url).asBitmap().centerCrop().into(new BitmapImageViewTarget(imageView) {
    @Override
    protected void setResource(Bitmap res) {
        RoundedBitmapDrawable bitmapDrawable =
             RoundedBitmapDrawableFactory.create(ctx.getResources(), res);
        bitmapDrawable.setCircular(true);//comment this line and uncomment the next line if you dont want it fully cricular
        //circularBitmapDrawable.setCornerRadius(cornerRadius);
        imageView.setImageDrawable(bitmapDrawable);
    }
});
Amir Ziarati
źródło
Jest to jednak elegancki interfejs API. Wydaje się, że brakuje .centerInside, dlatego być może lepiej jest użyć xml do zdefiniowania takich parametrów
carl
Jest to również przydatne, gdy obraz jest w zasobach i trzeba go użyćcenterCrop
Artyom
3

możesz użyć tylko ImageVieww swoim układzie i za glidepomocą tej metody możesz zastosować zaokrąglone rogi.

najpierw w pisaniu ocen,

compile 'com.github.bumptech.glide:glide:3.7.0'

dla obrazu z zaokrąglonymi narożnikami,

public void loadImageWithCorners(String url, ImageView view) {
    Glide.with(context)
            .load(url)
            .asBitmap()
            .centerCrop()
            .placeholder(R.color.gray)
            .error(R.color.gray)
            .diskCacheStrategy(DiskCacheStrategy.SOURCE)
            .into(new BitmapImageViewTarget(view) {
                @Override
                protected void setResource(Bitmap resource) {
                    RoundedBitmapDrawable circularBitmapDrawable =
                            RoundedBitmapDrawableFactory.create(context.getResources(), resource);
                    circularBitmapDrawable.setCornerRadius(32.0f); // radius for corners
                    view.setImageDrawable(circularBitmapDrawable);
                }
            });
}

metoda wywołania:

loadImageWithCorners("your url","your imageview");
Deep Patel
źródło
Spowoduje to dodanie biblioteki do ładowania obrazów za pośrednictwem żądania HTTP, co nie ma związku z pytaniem.
creativecreatorormaybenot
Która biblioteka zostanie załadowana? Do wczytywania obrazu możesz użyć poślizgu i jego fragmentu wyłącznie w oparciu o metody i klasy samego ślizgu. Żadnej innej biblioteki nie trzeba dodawać
Deep Patel
Glide to biblioteka przeznaczona głównie do ładowania obrazów przez HTTP, ale OP chciała wiedzieć, jak zaokrąglać rogi ImageView.
creativecreatorormaybenot
2

Odpowiedz na przekierowane tutaj pytanie: „Jak utworzyć okrągły ImageView w systemie Android?”

public static Bitmap getRoundBitmap(Bitmap bitmap) {

    int min = Math.min(bitmap.getWidth(), bitmap.getHeight());

    Bitmap bitmapRounded = Bitmap.createBitmap(min, min, bitmap.getConfig());

    Canvas canvas = new Canvas(bitmapRounded);
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
    canvas.drawRoundRect((new RectF(0.0f, 0.0f, min, min)), min/2, min/2, paint);

    return bitmapRounded;
}
Andrey
źródło
2

Za pomocą biblioteki glide i klasy RoundedBitmapDrawableFactory można to łatwo osiągnąć. Może być konieczne utworzenie okrągłego obrazu zastępczego.

    Glide.with(context)
        .load(imgUrl)
        .asBitmap()
        .placeholder(R.drawable.placeholder)
        .error(R.drawable.placeholder)
        .into(new BitmapImageViewTarget(imgProfilePicture) {
            @Override
            protected void setResource(Bitmap resource) {
                RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(),
                        Bitmap.createScaledBitmap(resource, 50, 50, false));
                drawable.setCornerRadius(10); //drawable.setCircular(true);
                imgProfilePicture.setImageDrawable(drawable);
            }
        });
Chitrang
źródło
2

Dla tych, którzy używają Glide i Kotlin, możesz to osiągnąć poprzez rozszerzenie RequestBuilder

fun <T> GlideRequest<T>.roundCorners(cornerRadius: Int) =
    apply(RequestOptions().transform(RoundedCorners(cornerRadius)))

i użyj jako;

 GlideApp.with(context)
            .load(url)
            .roundCorners(context.resources.getDimension(R.dimen.radius_in_dp).toInt())
            .into(imgView)
dgngulcan
źródło
.roundedCorners nie nadchodzi, czy musimy skonfigurować coś jeszcze?
Dr aNdRO,
czy dodałeś funkcję rozszerzenia roundCornersjak wyżej? @ Dr.aNdRO
dgngulcan
Podaj właściwy przykład! Ta odpowiedź jest myląca!
Junia Montana