Как реализовать Elevation Material-Design для Pre-lollipop

Google показал несколько хороших способов, что эффект возвышения показан на Lollipop здесь .

android:elevation="2dp" 

для кнопок,

 android:stateListAnimator="@anim/button_state_list_animator" 

Как я могу имитировать эффект возвышения на версиях до Lollipop без сторонней библиотеки?

Вы можете имитировать возвышение на пред-Lollipop официальным методом.

Я получаю такой же эффект, используя,

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

Мой тестовый результат:

введите описание изображения здесь

ссылка – https://stackoverflow.com/a/25683148/3879847

Благодаря пользователю @Repo ..

Обновление: если вы хотите изменить цвет этого рисунка, попробуйте ответить @Irfan ниже ↓

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

Вы не можете имитировать возвышение на пред-Lollipop официальным методом.

Вы можете использовать некоторые чертежи, чтобы сделать тень в своем компоненте. Например, Google использует этот способ в CardView.

ViewCompat.setElevation(View, int) настоящее время создает тень только для API21 +. Если вы проверите код позади, этот метод вызывает:

API 21+:

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

API <21

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

Вы можете взломать его с помощью карточного вида:

    

Или посмотрите на использование этой сторонней библиотеки: https://github.com/rey5137/Material (см. Статью в вики на кнопке https://github.com/rey5137/Material/wiki/Button )

Создайте 9-патч- изображение с растяжимыми патчами, определенными на изображении с тенью вокруг него.

введите описание изображения здесь

Добавьте это изображение с 9 патчами в качестве фона вашей кнопки с отступом, чтобы тень была видна.

Вы можете найти некоторые предварительно определенные 9-патч-изображения (.9.png) здесь или здесь, откуда вы можете выбрать, настроить и скопировать на ваш проект.

Чтобы принести динамические, анимированные тени к устройствам pre-Lollipop, вам необходимо:

  1. Нарисуйте черную форму вида на bitmap
  2. Размытие этой формы с использованием высоты в радиусе. Вы можете сделать это с помощью RenderScript. Это не совсем метод Lollipop, но дает хорошие результаты и легко добавляется к существующим представлениям.
  3. Нарисуйте эту размытую форму под видом. Вероятно, лучшим местом является метод drawChild . Вы также должны переопределить setElevation и setTranslationZ , переопределить чертеж детского представления в макетах, отключить клип-на-padding и реализовать аниматоры состояния.

введите описание изображения здесь

Это большая работа, но она дает лучшие, динамичные тени с анимацией ответа. Я не уверен, почему вы хотели бы добиться этого без сторонних библиотек. Если вы хотите, вы можете проанализировать источники Carbon и портировать части, которые вы хотели бы иметь в своем приложении:

Генерация тени

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

API высот, поддерживаемый до Lollipop

 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 Kumar ответ

Чтобы добавить фоновый цвет к выделенному (например, цвет фона кнопки), нам нужно сделать программно запрограммированным.

сначала получить ansible

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

в случае, если кто-либо ищет.

u может легко имитировать его, объявив, что это можно сделать так:

shadow.xml

     

и использовать его int ur main xml like –

  android:background="@drawable/shadow" 
Interesting Posts

CRTP, чтобы избежать динамического polymorphismа

Обложки iPhone для iPhone UITextField

Самый быстрый способ проверить, существует ли файл с использованием стандартного C ++ / C ++ 11 / C?

Трассировка стека или дополнительная информация о необработанном исключении в Xcode / iPhone

Невозможно отобразить PDF из HTTPS в IE 8 (на 64-разрядной версии Vista)

В C # проверьте, что имя файла * возможно * действительное (не то, что оно существует)

Можно ли экспортировать функции из C # DLL, как в VS C ++?

Символьная ссылка Windows на исполняемый файл – не открывается двойным щелчком

Установка Visual Studio 2010 (любая версия) устанавливает только 2 файла в каталоге заголовков C ++

Глобальная переменная в нескольких файлах

objective ACTION_VIEW для файла с неизвестным MimeType

Есть ли способ повторно включить панель управления Mac OS X?

Начало работы с открытым эмулятором NFC

Как можно отключить проверку орфографии для части страницы OneNote

Является ли законным возвращаться в main () на C ++?

Давайте будем гением компьютера.