To nie działa jak już ustawiłeś, jest to tło, więc treść zastępuje zaokrąglone rogi, a jeśli masz zawartość, która rysuje na rogach, nie zobaczysz, że są zaokrąglane.
programista Androida
22
Niemal zawsze moje treści nigdy nie obejmują narożników. To działa idealnie.
David JY Tang
2
Jak uniknąć błędu Element shape doesn't have the required attribute android:layout_height?
Lorenz
2
Element shape doesn't have the required attribute android:layout_heightPrzyczyna błędu została pokazana, ponieważ layout_bg.xml nie znajdował się w folderze rozwijalnym.
Atul
8
@ nhouser9: w rzeczywistości jest to bardziej „Działa, ale ostrzegam, że Twój pierwszy plan / treść może rysować się w rogach”. Zatem w zależności od przypadku użycia może działać w 100%. Cieszę się, że odpowiedź nie ma tylu głosów negatywnych, ponieważ jest przydatna, i cieszę się, że komentarz ma sto głosów pozytywnych, ponieważ dzięki temu rozwiązaniu łatwo jest dostrzec ograniczenia. Najlepsze z obu światów.
Benoit Duffez
124
W przypadku interfejsu API 21+ użyj widoków klipu
Zaokrąglone obcinanie obrysu zostało dodane do Viewklasy w API 21. Zobacz ten dokument szkoleniowy lub to odniesienie, aby uzyskać więcej informacji.
Ta wbudowana funkcja sprawia, że zaokrąglone rogi są bardzo łatwe do wdrożenia. Działa na dowolnym widoku lub układzie i obsługuje prawidłowe obcinanie.
Oto co należy zrobić:
Utwórz zaokrąglony kształt do rysowania i ustaw go jako tło widoku:
android:background="@drawable/round_outline"
Zgodnie z dokumentacją wszystko, co musisz zrobić, to: android:clipToOutline="true"
Niestety wydaje się, że wystąpił błąd i ten atrybut XML obecnie nie jest rozpoznawany. Na szczęście możemy ustawić przycinanie w Javie:
W Twojej działalności lub fragmencie: View.setClipToOutline(true)
Jak to wygląda:
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 tła jako obramowanie do celów wycinania i cieniowania.
Oznacza to, że jeśli chcesz zaokrąglać rogi w ImageView za pomocą setClipToOutline(), twój obraz musi pochodzić android:srczamiast android:background(ponieważ tło jest używane dla zaokrąglonego kształtu). Jeśli MUSISZ użyć tła do ustawienia obrazu zamiast src, możesz użyć tego obejścia widoków zagnieżdżonych:
Utwórz układ zewnętrzny z ustawionym tłem do kształtu do rysowania
Zawiń ten układ wokół ImageView (bez wypełnienia)
ImageView (włączając wszystko inne w układzie) zostanie teraz przycięty do zaokrąglonego kształtu zewnętrznego układu.
Nie działa na API mniejszym niż 21. Nie mogę się doczekać, aż będę mógł obsługiwać tylko API 21.
startoftext
Korzystanie z „setClipToOutline” działa, ale usuwa również samą ramkę (rysunek, którego używasz jako tła). Czy jest jakiś sposób, aby tego uniknąć?
programista Androida
Czy czytałeś moją notatkę o używaniu src=@drawable...zamiast background=@drawable? Możesz to zrobić lub zagnieździć ImageView w widoku kontenera, który zawiera kontur kształtu.
hungryghost
9
Wszyscy komentują ten błąd - ma prawie trzy lata i nie wykazuje żadnych oznak, że zostanie naprawiony w tej dekadzie. Naciskajmy na to.
Josh Hansen
Jak nie można jeszcze naprawić tego błędu
P Fuster
74
Oto kopia pliku XML, aby utworzyć rysunek z białym tłem, czarną ramką i zaokrąglonymi narożnikami:
zapisz go jako plik xml w katalogu do rysowania, użyj go tak, jakbyś używał dowolnego tła do rysowania (ikony lub pliku zasobów), używając jego nazwy zasobu (R.drawable.your_xml_name)
Uwielbiałem możliwość zaokrąglania określonych rogów
Mercury
1
Ta odpowiedź jest w zasadzie odpowiedzią jak wyżej. Jedyną prawdziwą zmianą jest tutaj definicja każdego promienia narożnika, a biorąc pod uwagę jego tę samą wartość dla każdego narożnika, <corners android:radius="7dp" />
zapisałbym
jest to dla mnie NAJLEPSZA odpowiedź, ponieważ obejmuje dostępność zaokrąglania określonych narożników ... dobra robota, działa w 100%
Mahmoud Ayman
Rogi ImageView nie są zaokrąglone (przycięte), jak to rozwiązać?
Primož Kralj
Nadal działa we wrześniu 2019 r. Fajnie.
Nikolas Rieble,
36
Użyj CardView w bibliotece wsparcia dla Androida v7. Choć jest trochę ciężki, rozwiązuje wszystkie problemy i jest dość łatwy. W przeciwieństwie do metody rysowania tła, może skutecznie przycinać widoki podrzędne.
Znacznie lepiej dla wszystkich, którzy mogą sobie na to pozwolić, niż cokolwiek innego. Zaskakuje mnie to, że taka podstawowa rzecz nie jest częścią standardowych widoków Androida, jest podstawowym elementem CSS dla prawie każdej przeglądarki internetowej
Ben Philipp
29
Zrobiłem w ten sposób:
Sprawdź zrzut ekranu:
Utwórz plik do rysowania o nazwie custom_rectangle.xmlw folderze do rysowania :
To nie działa jak już ustawiłeś, jest to tło, więc treść zastępuje zaokrąglone rogi, a jeśli masz zawartość, która rysuje na rogach, nie zobaczysz, że są zaokrąglane.
programista Androida
25
Myślę, że lepszym sposobem na to jest połączenie dwóch rzeczy:
Zrobić zaokrąglony rysunek z mapy bitowej, jak pokazano tutaj
ustaw drawable na imageView.
Będzie to obsługiwać przypadki, których inne rozwiązania nie rozwiązały, na przykład zawartość o narożnikach.
Myślę, że jest też trochę bardziej przyjazny dla GPU, ponieważ pokazuje jedną warstwę zamiast 2.
Jedynym lepszym sposobem jest stworzenie całkowicie spersonalizowanego widoku, ale to dużo kodu i może zająć dużo czasu. Myślę, że to, co tu zasugerowałem, jest najlepsze z obu światów.
Oto fragment tego, jak można to zrobić:
RoundedCornersDrawable.java
/**
* shows a bitmap as if it had rounded corners. based on :
* http://rahulswackyworld.blogspot.co.il/2013/04/android-drawables-with-rounded_7.html
* easy alternative from support library: RoundedBitmapDrawableFactory.create( ...) ;
*/
public class RoundedCornersDrawable extends BitmapDrawable {
private final BitmapShader bitmapShader;
private final Paint p;
private final RectF rect;
private final float borderRadius;
public RoundedCornersDrawable(final Resources resources, final Bitmap bitmap, final float borderRadius) {
super(resources, bitmap);
bitmapShader = new BitmapShader(getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
final Bitmap b = getBitmap();
p = getPaint();
p.setAntiAlias(true);
p.setShader(bitmapShader);
final int w = b.getWidth(), h = b.getHeight();
rect = new RectF(0, 0, w, h);
this.borderRadius = borderRadius < 0 ? 0.15f * Math.min(w, h) : borderRadius;
}
@Override
public void draw(final Canvas canvas) {
canvas.drawRoundRect(rect, borderRadius, borderRadius, p);
}
}
CustomView.java
public class CustomView extends ImageView {
private View mMainContainer;
private boolean mIsDirty=false;
// TODO for each change of views/content, set mIsDirty to true and call invalidate
@Override
protected void onDraw(final Canvas canvas) {
if (mIsDirty) {
mIsDirty = false;
drawContent();
return;
}
super.onDraw(canvas);
}
/**
* draws the view's content to a bitmap. code based on :
* http://nadavfima.com/android-snippet-inflate-a-layout-draw-to-a-bitmap/
*/
public static Bitmap drawToBitmap(final View viewToDrawFrom, final int width, final int height) {
// Create a new bitmap and a new canvas using that bitmap
final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bmp);
viewToDrawFrom.setDrawingCacheEnabled(true);
// Supply measurements
viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(canvas.getWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(canvas.getHeight(), MeasureSpec.EXACTLY));
// Apply the measures so the layout would resize before drawing.
viewToDrawFrom.layout(0, 0, viewToDrawFrom.getMeasuredWidth(), viewToDrawFrom.getMeasuredHeight());
// and now the bmp object will actually contain the requested layout
canvas.drawBitmap(viewToDrawFrom.getDrawingCache(), 0, 0, new Paint());
return bmp;
}
private void drawContent() {
if (getMeasuredWidth() <= 0 || getMeasuredHeight() <= 0)
return;
final Bitmap bitmap = drawToBitmap(mMainContainer, getMeasuredWidth(), getMeasuredHeight());
final RoundedCornersDrawable drawable = new RoundedCornersDrawable(getResources(), bitmap, 15);
setImageDrawable(drawable);
}
}
EDYCJA: znalazłem fajną alternatywę, opartą na bibliotece „RoundKornersLayouts” . Mieć klasę, która będzie używana dla wszystkich klas układu, które chcesz rozszerzyć, aby ją zaokrąglić:
//based on https://github.com/JcMinarro/RoundKornerLayouts
class CanvasRounder(cornerRadius: Float, cornerStrokeColor: Int = 0, cornerStrokeWidth: Float = 0F) {
private val path = android.graphics.Path()
private lateinit var rectF: RectF
private var strokePaint: Paint?
var cornerRadius: Float = cornerRadius
set(value) {
field = value
resetPath()
}
init {
if (cornerStrokeWidth <= 0)
strokePaint = null
else {
strokePaint = Paint()
strokePaint!!.style = Paint.Style.STROKE
strokePaint!!.isAntiAlias = true
strokePaint!!.color = cornerStrokeColor
strokePaint!!.strokeWidth = cornerStrokeWidth
}
}
fun round(canvas: Canvas, drawFunction: (Canvas) -> Unit) {
val save = canvas.save()
canvas.clipPath(path)
drawFunction(canvas)
if (strokePaint != null)
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, strokePaint)
canvas.restoreToCount(save)
}
fun updateSize(currentWidth: Int, currentHeight: Int) {
rectF = android.graphics.RectF(0f, 0f, currentWidth.toFloat(), currentHeight.toFloat())
resetPath()
}
private fun resetPath() {
path.reset()
path.addRoundRect(rectF, cornerRadius, cornerRadius, Path.Direction.CW)
path.close()
}
}
Następnie w każdej z niestandardowych klas układu dodaj kod podobny do tego:
Inna alternatywa, która może być łatwiejsza w przypadku większości zastosowań: użyj MaterialCardView. Pozwala dostosować zaokrąglone rogi, kolor i szerokość obrysu oraz wysokość.
Zauważ, że na krawędziach obrysu występuje niewielki problem z artefaktami (pozostawia tam kilka pikseli zawartości), jeśli go używasz. Możesz to zauważyć, jeśli powiększysz. Zgłosiłem tutaj ten problem .
EDYCJA: wydaje się być naprawiona, ale nie na IDE. Zgłoszone tutaj .
Dziękuję za zebranie tej niesamowitej odpowiedzi. To sprawiło, że zmierzałem we właściwym kierunku, ale mogłem skorzystać z pomocy w bardzo pokrewnym problemie tutaj stackoverflow.com/questions/25877515/...
Will Thomson
Daje to błąd, ponieważ w ImageView nie ma domyślnego konstruktora.
Anuj,
Należy zaakceptować odpowiedź. Zamiast płaskiej logiki poszedłeś w dół i znalazłeś niesamowite rozwiązanie. To także rozwiązuje problemy wymienione w komentarzach do innych odpowiedzi. Dzięki za twój wysiłek, a może uda Ci się wykupić w pełni funkcjonalną klasę i udostępnić ją za pośrednictwem github. Myślę, że może pomóc zbyt wielu ludziom.
Tak jak napisałem powyżej o podobnym rozwiązaniu: To nie działa. jak już ustawiłeś, jest to tło, więc treść zastępuje zaokrąglone rogi, a jeśli masz zawartość, która rysuje na rogach, nie zobaczysz, że są zaokrąglane.
programista Androida
9
Jeśli chcesz, aby Twój układ był zaokrąglony, najlepiej użyć CardView, ponieważ zapewnił wiele funkcji, aby projekt był piękny.
Najlepszym i najprostszym sposobem byłoby wykorzystanie card_background rozciągliwej w układzie. Jest to również zgodne z wytycznymi Google dotyczącymi projektowania materiałów. Po prostu dołącz to do siebie LinearLayout:
android:background="@drawable/card_background"
Dodaj to do katalogu, który można wyciągnąć i nazwij go card_background.xml :
Użyj CardView, aby uzyskać zaokrąglone krawędzie dla dowolnych układów. Użyj card_view: cardCornerRadius = "5dp" dla widoku karty, aby uzyskać zaokrąglone krawędzie układu.
To zadziała również poniżej API 21 i da ci coś takiego:
Jeśli chcesz nieco więcej wysiłku, lepiej kontrolować, użyj android.support.v7.widget.CardViewtego cardCornerRadiusatrybutu (i ustaw elevationatrybut, 0dpaby pozbyć się towarzyszącego mu cienia za pomocą cardView). Będzie to również działać z poziomu interfejsu API już od 15.
Jeśli treść pasuje do tła, zastąpi ją. Tak naprawdę nie pasuje do ustawionego kształtu.
programista Androida
Masz na myśli inny widok? Czy możesz zaktualizować kod, aby pokazać, co masz na myśli? Chodzi o to, że zaokrąglone rogi nie umieszczałyby czarnego obszaru. Wokół rogów powinien być przezroczysty kolor.
programista Androida
Och, rozumiem teraz twoje pytanie. Sądzę, że możesz sobie
poradzić
Ale wtedy zawartość nie zostanie przycięta do wybranego kształtu, ponieważ ustalone marginesy są prostokątne, a nie zgodnie z wybranym kształtem.
Wziąłem odpowiedź @gauravsapiens z moimi komentarzami w środku, aby dać ci rozsądne zrozumienie, jakie parametry będą miały wpływ.
<?xml version="1.0" encoding="utf-8"?><shapexmlns:android="http://schemas.android.com/apk/res/android"><!-- Background color --><solidandroid:color="@color/white"/><!-- Stroke around the background, width and color --><strokeandroid:width="4dp"android:color="@color/drop_shadow"/><!-- The corners of the shape --><cornersandroid:radius="4dp"/><!-- Padding for the background, e.g the Text inside a TextView will be
located differently --><paddingandroid:left="10dp"android:right="10dp"android:bottom="10dp"android:top="10dp"/></shape>
Jeśli chcesz tylko utworzyć kształt, który zaokrągli rogi, usuń wypełnienie, a obrys się spełni. Jeśli usuniesz bryłę, utworzysz zaokrąglone rogi na przezroczystym tle.
Dla lenistwa stworzyłem pod spodem kształt, który jest po prostu białym tłem z zaokrąglonymi rogami - ciesz się! :)
<?xml version="1.0" encoding="utf-8"?><shapexmlns:android="http://schemas.android.com/apk/res/android"><!-- Background color --><solidandroid:color="@color/white"/><!-- The corners of the shape --><cornersandroid:radius="4dp"/></shape>
Stwórz swój plik xml w wersji do rysowania, layout_background.xml
<?xml version="1.0" encoding="utf-8"?><shapexmlns:android="http://schemas.android.com/apk/res/android"><solidandroid:color="@color/your_colour"/><strokeandroid:width="2dp"android:color="@color/your_colour"/><cornersandroid:radius="10dp"/></shape>
<--width, color, radius should be as per your requirement-->
Następnie w kodzie możesz zastosować ShapeAppearanceModel. Coś jak:
float radius = getResources().getDimension(R.dimen.default_corner_radius);
LinearLayout linearLayout= findViewById(R.id.linear_rounded);
ShapeAppearanceModel shapeAppearanceModel = new ShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED,radius)
.build();
MaterialShapeDrawable shapeDrawable = new MaterialShapeDrawable(shapeAppearanceModel);
//Fill the LinearLayout with your color
shapeDrawable.setFillColor(ContextCompat.getColorStateList(this,R.color.secondaryLightColor));
ViewCompat.setBackground(linearLayout,shapeDrawable);
Uwaga :: wymaga wersji 1.1.0 biblioteki komponentów materiałów.
Odpowiedzi:
1: Zdefiniuj layout_bg.xml w drawables:
2: Dodaj
layout_bg.xml
jako tło do swojego układuźródło
Element shape doesn't have the required attribute android:layout_height
?Element shape doesn't have the required attribute android:layout_height
Przyczyna błędu została pokazana, ponieważ layout_bg.xml nie znajdował się w folderze rozwijalnym.W przypadku interfejsu API 21+ użyj widoków klipu
Zaokrąglone obcinanie obrysu zostało dodane do
View
klasy w API 21. Zobacz ten dokument szkoleniowy lub to odniesienie, aby uzyskać więcej informacji.Ta wbudowana funkcja sprawia, że zaokrąglone rogi są bardzo łatwe do wdrożenia. Działa na dowolnym widoku lub układzie i obsługuje prawidłowe obcinanie.
Oto co należy zrobić:
android:background="@drawable/round_outline"
android:clipToOutline="true"
Niestety wydaje się, że wystąpił błąd i ten atrybut XML obecnie nie jest rozpoznawany. Na szczęście możemy ustawić przycinanie w Javie:
View.setClipToOutline(true)
Jak to wygląda:
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 tła jako obramowanie do celów wycinania i cieniowania.Oznacza to, że jeśli chcesz zaokrąglać rogi w ImageView za pomocą
setClipToOutline()
, twój obraz musi pochodzićandroid:src
zamiastandroid:background
(ponieważ tło jest używane dla zaokrąglonego kształtu). Jeśli MUSISZ użyć tła do ustawienia obrazu zamiast src, możesz użyć tego obejścia widoków zagnieżdżonych:źródło
src=@drawable...
zamiastbackground=@drawable
? Możesz to zrobić lub zagnieździć ImageView w widoku kontenera, który zawiera kontur kształtu.Oto kopia pliku XML, aby utworzyć rysunek z białym tłem, czarną ramką i zaokrąglonymi narożnikami:
zapisz go jako plik xml w katalogu do rysowania, użyj go tak, jakbyś używał dowolnego tła do rysowania (ikony lub pliku zasobów), używając jego nazwy zasobu (R.drawable.your_xml_name)
źródło
<corners android:radius="7dp" />
Użyj CardView w bibliotece wsparcia dla Androida v7. Choć jest trochę ciężki, rozwiązuje wszystkie problemy i jest dość łatwy. W przeciwieństwie do metody rysowania tła, może skutecznie przycinać widoki podrzędne.
źródło
Zrobiłem w ten sposób:
Sprawdź zrzut ekranu:
Utwórz plik do rysowania o nazwie
custom_rectangle.xml
w folderze do rysowania :Teraz zastosuj tło prostokąta w widoku :
Gotowy
źródło
Myślę, że lepszym sposobem na to jest połączenie dwóch rzeczy:
zrób bitmapę układu, jak pokazano tutaj .
Zrobić zaokrąglony rysunek z mapy bitowej, jak pokazano tutaj
ustaw drawable na imageView.
Będzie to obsługiwać przypadki, których inne rozwiązania nie rozwiązały, na przykład zawartość o narożnikach.
Myślę, że jest też trochę bardziej przyjazny dla GPU, ponieważ pokazuje jedną warstwę zamiast 2.
Jedynym lepszym sposobem jest stworzenie całkowicie spersonalizowanego widoku, ale to dużo kodu i może zająć dużo czasu. Myślę, że to, co tu zasugerowałem, jest najlepsze z obu światów.
Oto fragment tego, jak można to zrobić:
RoundedCornersDrawable.java
CustomView.java
EDYCJA: znalazłem fajną alternatywę, opartą na bibliotece „RoundKornersLayouts” . Mieć klasę, która będzie używana dla wszystkich klas układu, które chcesz rozszerzyć, aby ją zaokrąglić:
Następnie w każdej z niestandardowych klas układu dodaj kod podobny do tego:
Jeśli chcesz obsługiwać atrybuty, użyj tego, jak napisano w bibliotece:
Inna alternatywa, która może być łatwiejsza w przypadku większości zastosowań: użyj MaterialCardView. Pozwala dostosować zaokrąglone rogi, kolor i szerokość obrysu oraz wysokość.
Przykład:
A wynik:
Zauważ, że na krawędziach obrysu występuje niewielki problem z artefaktami (pozostawia tam kilka pikseli zawartości), jeśli go używasz. Możesz to zauważyć, jeśli powiększysz. Zgłosiłem tutaj ten problem .
EDYCJA: wydaje się być naprawiona, ale nie na IDE. Zgłoszone tutaj .
źródło
Spróbuj tego...
1. stwórz xml do rysowania (custom_layout.xml):
2. dodaj swoje tło widoku
źródło
Jeśli chcesz, aby Twój układ był zaokrąglony, najlepiej użyć CardView, ponieważ zapewnił wiele funkcji, aby projekt był piękny.
Za pomocą tego card_view: cardCornerRadius = "5dp" możesz zmienić promień.
źródło
Najlepszym i najprostszym sposobem byłoby wykorzystanie card_background rozciągliwej w układzie. Jest to również zgodne z wytycznymi Google dotyczącymi projektowania materiałów. Po prostu dołącz to do siebie LinearLayout:
Dodaj to do katalogu, który można wyciągnąć i nazwij go card_background.xml :
źródło
Użyj CardView, aby uzyskać zaokrąglone krawędzie dla dowolnych układów. Użyj card_view: cardCornerRadius = "5dp" dla widoku karty, aby uzyskać zaokrąglone krawędzie układu.
źródło
Lepszym sposobem na to byłoby:
background_activity.xml
To zadziała również poniżej API 21 i da ci coś takiego:
Jeśli chcesz nieco więcej wysiłku, lepiej kontrolować, użyj
android.support.v7.widget.CardView
tegocardCornerRadius
atrybutu (i ustawelevation
atrybut,0dp
aby pozbyć się towarzyszącego mu cienia za pomocą cardView). Będzie to również działać z poziomu interfejsu API już od 15.źródło
Funkcja programowego ustawiania promienia narożnika
Za pomocą
źródło
@ David, po prostu wstaw padding taką samą wartość jak obrys, aby ramka była widoczna, bez względu na rozmiar obrazu
źródło
Wziąłem odpowiedź @gauravsapiens z moimi komentarzami w środku, aby dać ci rozsądne zrozumienie, jakie parametry będą miały wpływ.
Jeśli chcesz tylko utworzyć kształt, który zaokrągli rogi, usuń wypełnienie, a obrys się spełni. Jeśli usuniesz bryłę, utworzysz zaokrąglone rogi na przezroczystym tle.
Dla lenistwa stworzyłem pod spodem kształt, który jest po prostu białym tłem z zaokrąglonymi rogami - ciesz się! :)
źródło
Stwórz swój plik xml w wersji do rysowania,
layout_background.xml
a następnie dodaj to do swojego
layout.xml
źródło
Za pomocą Biblioteki komponentów materiałów możesz używać
MaterialShapeDrawable
do rysowania niestandardowych kształtów .Wystarczy umieścić LinearLayout w układzie xml:
Następnie w kodzie możesz zastosować
ShapeAppearanceModel
. Coś jak:Uwaga :: wymaga wersji 1.1.0 biblioteki komponentów materiałów.
źródło
źródło