Google a montré de belles façons de montrer l'effet d'élévation sur Lollipop ici .
Android:elevation="2dp"
pour les boutons,
Android:stateListAnimator="@anim/button_state_list_animator"
Comment puis-je imiter l'effet d'altitude sur les versions antérieures à Lollipop sans bibliothèque tierce?
Vous pouvez imiter l'élévation avant Lollipop avec une méthode officielle.
J'obtiens le même effet en utilisant,
Android:background="@Android:drawable/dialog_holo_light_frame"
Ma sortie testée:
référence - https://stackoverflow.com/a/25683148/3879847
Merci à l'utilisateur @Repo ..
Mise à jour: Si vous souhaitez modifier la couleur de cet dessin, essayez la réponse @Irfan ci-dessous
Vous ne pouvez pas imiter l'élévation sur pré-Lollipop avec une méthode officielle.
Vous pouvez utiliser certains éléments dessinables pour créer l’ombre dans votre composant. Google utilise cette manière dans CardView par exemple.
La ViewCompat.setElevation(View, int)
crée actuellement l'ombre uniquement sur API21 +. Si vous vérifiez le code derrière, cette méthode appelle:
API 21 +:
@Override
public void setElevation(View view, float elevation) {
ViewCompatLollipop.setElevation(view, elevation);
}
API <21
@Override
public void setElevation(View view, float elevation) {
}
Vous pouvez soit le pirater en utilisant une vue de carte:
<Android.support.v7.widget.CardView
xmlns:card_view="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/btnGetStuff"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp"
card_view:cardBackgroundColor="@color/accent"
>
<!-- you could also add image view here for icon etc. -->
<TextView
Android:id="@+id/txtGetStuff"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:textSize="@dimen/textSize_small"
Android:textColor="@color/primary_light"
Android:freezesText="true"
Android:text="Get Stuff"
Android:maxWidth="120dp"
Android:singleLine="true"
Android:ellipsize="end"
Android:maxLines="1"
/></Android.support.v7.widget.CardView>
Ou utilisez cette bibliothèque tierce: https://github.com/rey5137/Material (voir l'article du wiki sur le bouton https://github.com/rey5137/Material/wiki/Bouton )
Pour créer des ombres dynamiques et animées sur les appareils pré-Lollipop, vous devez:
drawChild
. Vous devez également redéfinir setElevation
et setTranslationZ
, redéfinir le dessin de la vue enfant dans les mises en forme, désactiver les animateurs de clip-to-padding et implémenter les états.C'est beaucoup de travail, mais cela donne les meilleurs ombres dynamiques avec des animations de réponse. Je ne sais pas pourquoi vous voudriez y parvenir sans bibliothèques tierces. Si vous le souhaitez, vous pouvez analyser les sources de carbone et transférer les pièces que vous souhaitez inclure dans votre application:
private static void blurRenderScript(Bitmap bitmap, float radius) {
Allocation inAllocation = Allocation.createFromBitmap(renderScript, bitmap,
Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
Allocation outAllocation = Allocation.createTyped(renderScript, inAllocation.getType());
blurShader.setRadius(radius);
blurShader.setInput(inAllocation);
blurShader.forEach(outAllocation);
outAllocation.copyTo(bitmap);
}
public static Shadow generateShadow(View view, float elevation) {
if (!software && renderScript == null) {
try {
renderScript = RenderScript.create(view.getContext());
blurShader = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript));
} catch (RSRuntimeException ignore) {
software = true;
}
}
ShadowView shadowView = (ShadowView) view;
CornerView cornerView = (CornerView) view;
boolean isRect = shadowView.getShadowShape() == ShadowShape.RECT ||
shadowView.getShadowShape() == ShadowShape.ROUND_RECT && cornerView.getCornerRadius() < view.getContext().getResources().getDimension(R.dimen.carbon_1dip) * 2.5;
int e = (int) Math.ceil(elevation);
Bitmap bitmap;
if (isRect) {
bitmap = Bitmap.createBitmap(e * 4 + 1, e * 4 + 1, Bitmap.Config.ARGB_8888);
Canvas shadowCanvas = new Canvas(bitmap);
Paint.setStyle(Paint.Style.FILL);
Paint.setColor(0xff000000);
shadowCanvas.drawRect(e, e, e * 3 + 1, e * 3 + 1, Paint);
blur(bitmap, elevation);
return new NinePatchShadow(bitmap, elevation);
} else {
bitmap = Bitmap.createBitmap((int) (view.getWidth() / SHADOW_SCALE + e * 2), (int) (view.getHeight() / SHADOW_SCALE + e * 2), Bitmap.Config.ARGB_8888);
Canvas shadowCanvas = new Canvas(bitmap);
Paint.setStyle(Paint.Style.FILL);
Paint.setColor(0xff000000);
if (shadowView.getShadowShape() == ShadowShape.ROUND_RECT) {
roundRect.set(e, e, (int) (view.getWidth() / SHADOW_SCALE - e), (int) (view.getHeight() / SHADOW_SCALE - e));
shadowCanvas.drawRoundRect(roundRect, e, e, Paint);
} else {
int r = (int) (view.getWidth() / 2 / SHADOW_SCALE);
shadowCanvas.drawCircle(r + e, r + e, r, Paint);
}
blur(bitmap, elevation);
return new Shadow(bitmap, elevation);
}
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if (!child.isShown())
return super.drawChild(canvas, child, drawingTime);
if (!isInEditMode() && child instanceof ShadowView && Build.VERSION.SDK_INT <= Build.VERSION_CODES.KitKat_WATCH) {
ShadowView shadowView = (ShadowView) child;
Shadow shadow = shadowView.getShadow();
if (shadow != null) {
Paint.setAlpha((int) (ShadowGenerator.ALPHA * ViewHelper.getAlpha(child)));
float childElevation = shadowView.getElevation() + shadowView.getTranslationZ();
float[] childLocation = new float[]{(child.getLeft() + child.getRight()) / 2, (child.getTop() + child.getBottom()) / 2};
Matrix matrix = carbon.internal.ViewHelper.getMatrix(child);
matrix.mapPoints(childLocation);
int[] location = new int[2];
getLocationOnScreen(location);
float x = childLocation[0] + location[0];
float y = childLocation[1] + location[1];
x -= getRootView().getWidth() / 2;
y += getRootView().getHeight() / 2; // looks Nice
float length = (float) Math.sqrt(x * x + y * y);
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(
x / length * childElevation / 2,
y / length * childElevation / 2);
canvas.translate(
child.getLeft(),
child.getTop());
canvas.concat(matrix);
canvas.scale(ShadowGenerator.SHADOW_SCALE, ShadowGenerator.SHADOW_SCALE);
shadow.draw(canvas, child, Paint);
canvas.restoreToCount(saveCount);
}
}
if (child instanceof RippleView) {
RippleView rippleView = (RippleView) child;
RippleDrawable rippleDrawable = rippleView.getRippleDrawable();
if (rippleDrawable != null && rippleDrawable.getStyle() == RippleDrawable.Style.Borderless) {
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(
child.getLeft(),
child.getTop());
rippleDrawable.draw(canvas);
canvas.restoreToCount(saveCount);
}
}
return super.drawChild(canvas, child, drawingTime);
}
private float elevation = 0;
private float translationZ = 0;
private Shadow shadow;
@Override
public float getElevation() {
return elevation;
}
public synchronized void setElevation(float elevation) {
if (elevation == this.elevation)
return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop)
super.setElevation(elevation);
this.elevation = elevation;
if (getParent() != null)
((View) getParent()).postInvalidate();
}
@Override
public float getTranslationZ() {
return translationZ;
}
public synchronized void setTranslationZ(float translationZ) {
if (translationZ == this.translationZ)
return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop)
super.setTranslationZ(translationZ);
this.translationZ = translationZ;
if (getParent() != null)
((View) getParent()).postInvalidate();
}
@Override
public ShadowShape getShadowShape() {
if (cornerRadius == getWidth() / 2 && getWidth() == getHeight())
return ShadowShape.CIRCLE;
if (cornerRadius > 0)
return ShadowShape.ROUND_RECT;
return ShadowShape.RECT;
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
setTranslationZ(enabled ? 0 : -elevation);
}
@Override
public Shadow getShadow() {
float elevation = getElevation() + getTranslationZ();
if (elevation >= 0.01f && getWidth() > 0 && getHeight() > 0) {
if (shadow == null || shadow.elevation != elevation)
shadow = ShadowGenerator.generateShadow(this, elevation);
return shadow;
}
return null;
}
@Override
public void invalidateShadow() {
shadow = null;
if (getParent() != null && getParent() instanceof View)
((View) getParent()).postInvalidate();
}
Créez une image 9-patch avec des patchs extensibles définis sur une image entourée d’ombre.
Ajoutez cette image de 9 patchs en tant qu'arrière-plan de votre bouton avec un rembourrage pour que l'ombre soit visible.
Vous pouvez trouver des images prédéfinies de 9 correctifs (.9.png) ici ou ici à partir desquelles vous pouvez sélectionner, personnaliser et copier le dessin de votre projet.
ajouter @Ranjith Kumar answer
Pour ajouter une couleur d’arrière-plan au dessinable (exemple: couleur d’arrière-plan du bouton), vous devez le faire par programmation.
d'abord obtenir le drawable
Drawable drawable = getResources().getDrawable(Android.R.drawable.dialog_holo_light_frame);
définir la couleur
drawable.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.color_primary), PorterDuff.Mode.MULTIPLY));
puis définissez-le à la vue.
view.setBackgroundDrawable(drawable);
au cas où quelqu'un cherche.
vous pouvez facilement simuler en déclarant un drawable comme celui-ci -
shadow.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:Android="http://schemas.Android.com/apk/res/Android"
>
<gradient Android:type="linear" Android:angle="270" Android:startColor="#b6b6b6" Android:endColor="#ffffff"/>
</shape>
et l'utiliser int ur principal xml comme -
Android:background="@drawable/shadow"