如何实施棒棒糖的材料devise高程

谷歌已经展示了一些很棒的方式,在这里棒棒糖显示的海拔效果。

android:elevation="2dp" 

对于button,

 android:stateListAnimator="@anim/button_state_list_animator" 

如何在没有第三方库的情况下模仿Lollipop版本的海拔效果?

Solutions Collecting From Web of "如何实施棒棒糖的材料devise高程"

你可以用官方的方法来模拟Lollipop之前的高程。

我使用同样的效果,

  android:background="@android:drawable/dialog_holo_light_frame" 

我的testing结果:

在这里输入图像说明

参考 – https://stackoverflow.com/a/25683148/3879847

感谢用户@Repo ..

更新:如果你想改变这个可绘的颜色尝试@Irfan答案↓下面

https://stackoverflow.com/a/40815944/3879847

你不能用正式的方法来模拟前棒棒糖上的高程。

您可以使用一些可绘制的元素来创build组件中的阴影。 Google在CardView中使用这种方式。

ViewCompat.setElevation(View, int)当前只在API21 +上创build阴影。 如果你检查后面的代码,这个方法调用:

API 21+:

  @Override public void setElevation(View view, float elevation) { ViewCompatLollipop.setElevation(view, elevation); } 

API <21

 @Override public void setElevation(View view, float elevation) { } 

你可以使用卡片视图来破解它:

 <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> 

或者看看使用这个第三方库: https : //github.com/rey5137/Material (请参阅button上的wiki文章https://github.com/rey5137/Material/wiki/Button

用带有阴影的图像定义的可伸缩贴片创build9贴片图像。

在这里输入图像说明

使用填充将此9补丁图像作为button的背景添加,以便阴影可见。

您可以在这里或这里find一些预定义的9-patch(.9.png)图像,您可以从中select,自定义和复制到您的项目的绘图。

要将dynamic阴影带到棒棒糖设备之前,您必须:

  1. 绘制一个黑色的形状的视图到位图
  2. 模糊使用高程作为半径的形状。 你可以使用RenderScript来做到这一点。 这不完全是棒棒糖使用的方法,但是可以带来很好的效果,而且很容易添加到现有的视图中。
  3. 在视图下方绘制模糊的形状。 可能最好的地方是drawChild方法。 您还必须覆盖setElevationsetTranslationZ ,覆盖布局中的子视图绘图,closures剪辑间填充和实现状态animation。

在这里输入图像说明

这是一个很大的工作,但它提供了最好看,dynamic阴影与响应animation。 我不确定为什么你想在没有第三方库的情况下实现这个目标。 如果你愿意,你可以分析碳的来源,并移植你想要在你的应用程序中的部分:

影子一代

 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); } 

Elevation API被回传到棒棒堂前

 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(); } 

添加@Ranjith库马尔答案

为了给drawable添加背景颜色(例如button背景颜色),我们需要以编程方式获取drawable。

首先得到drawable

 Drawable drawable = getResources().getDrawable(android.R.drawable.dialog_holo_light_frame); 

设置颜色

 drawable.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.color_primary), PorterDuff.Mode.MULTIPLY)); 

然后将其设置为视图。

 view.setBackgroundDrawable(drawable); 

如果有人search。

你可以很容易地通过声明一个可绘制的模拟它 –

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> 

并使用它你主要的XML像 –

  android:background="@drawable/shadow"