2015-11-07 3 views
0

Я использовал библиотеку дизайна материалов для Android, чтобы сделать полосу табуляции следующим образом.Как уклониться от теневого направления Android 5 Lollipop

enter image description here

Я добавил вид в нижней части экрана, как это.

enter image description here

Прямо сейчас, я пытаюсь добавить эффект тени от верхнего элемента к нижней панели.

Я нашел решение в форме ответа на вопрос this question.

Единственный способ, с помощью которого я создал верхнюю тень, - это изменить часть источника проекта AndroidView v7 CardView для Android. Этот проект приносит класс CardView к более старым версиям Android и, следовательно, также включает в себя тень высот. Полученная тень очень близка к «реальной» отметке высоты.

Я следовал инструкциям, и я закончил со следующим результатом использовать иллюстрации

enter image description here

Я добавил эти цвета res/values/values.xml

<color name="cardview_shadow_end_color">#03000000</color> 
<color name="cardview_shadow_start_color">#47000000</color> 
<dimen name="cardview_compat_inset_shadow">1dp</dimen> 

И я использовал класс RoundRectDrawableWithShadow от измененного Android v7 проекта CardView для установки тени

Вот мой доработанный код CardView проект RoundRectDrawableWithShadow класс

/* 
* Copyright (C) 2014 The Android Open Source Project 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
*  http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*/ 

import android.graphics.RectF; 
import android.content.res.Resources; 
import android.graphics.Canvas; 
import android.graphics.ColorFilter; 
import android.graphics.LinearGradient; 
import android.graphics.Paint; 
import android.graphics.Path; 
import android.graphics.PixelFormat; 
import android.graphics.RadialGradient; 
import android.graphics.Rect; 
import android.graphics.RectF; 
import android.graphics.Shader; 
import android.graphics.drawable.Drawable; 


/** 
* A rounded rectangle drawable which also includes a shadow around. 
*/ 
public class RoundRectDrawableWithShadow extends Drawable { 
    // used to calculate content padding 
    final static double COS_45 = Math.cos(Math.toRadians(45)); 

    final static float SHADOW_MULTIPLIER = 1.5f; 

    final int mInsetShadow; // extra shadow to avoid gaps between card and shadow 

    /* 
    * This helper is set by CardView implementations. 
    * <p> 
    * Prior to API 17, canvas.drawRoundRect is expensive; which is why we need this interface 
    * to draw efficient rounded rectangles before 17. 
    * */ 
    static RoundRectHelper sRoundRectHelper; 

    Paint mPaint; 

    Paint mCornerShadowPaint; 

    Paint mEdgeShadowPaint; 

    final RectF mCardBounds; 

    float mCornerRadius; 

    Path mCornerShadowPath; 

    // updated value with inset 
    float mMaxShadowSize; 

    // actual value set by developer 
    float mRawMaxShadowSize; 

    // multiplied value to account for shadow offset 
    float mShadowSize; 

    // actual value set by developer 
    float mRawShadowSize; 

    private boolean mDirty = true; 

    private final int mShadowStartColor; 

    private final int mShadowEndColor; 

    private boolean mAddPaddingForCorners = true; 

    /** 
    * If shadow size is set to a value above max shadow, we print a warning 
    */ 
    private boolean mPrintedShadowClipWarning = false; 

    public RoundRectDrawableWithShadow(
      Resources resources, int backgroundColor, float radius, 
      float shadowSize, float maxShadowSize 
    ) { 
     mShadowStartColor = resources.getColor(R.color.cardview_shadow_start_color); 
     mShadowEndColor = resources.getColor(R.color.cardview_shadow_end_color); 
     mInsetShadow = resources.getDimensionPixelSize(R.dimen.cardview_compat_inset_shadow); 
     mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); 
     mPaint.setColor(backgroundColor); 
     mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); 
     mCornerShadowPaint.setStyle(Paint.Style.FILL); 
     mCornerRadius = (int) (radius + .5f); 
     mCardBounds = new RectF(); 
     mEdgeShadowPaint = new Paint(mCornerShadowPaint); 
     mEdgeShadowPaint.setAntiAlias(false); 
     setShadowSize(shadowSize, maxShadowSize); 

     RoundRectDrawableWithShadow.sRoundRectHelper 
       = new RoundRectDrawableWithShadow.RoundRectHelper() { 
      @Override 
      public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, 
             Paint paint) { 
       canvas.drawRoundRect(bounds, cornerRadius, cornerRadius, paint); 
      } 
     }; 
    } 

    /** 
    * Casts the value to an even integer. 
    */ 
    private int toEven(float value) { 
     int i = (int) (value + .5f); 
     if (i % 2 == 1) { 
      return i - 1; 
     } 
     return i; 
    } 

    public void setAddPaddingForCorners(boolean addPaddingForCorners) { 
     mAddPaddingForCorners = addPaddingForCorners; 
     invalidateSelf(); 
    } 

    @Override 
    public void setAlpha(int alpha) { 
     mPaint.setAlpha(alpha); 
     mCornerShadowPaint.setAlpha(alpha); 
     mEdgeShadowPaint.setAlpha(alpha); 
    } 

    @Override 
    protected void onBoundsChange(Rect bounds) { 
     super.onBoundsChange(bounds); 
     mDirty = true; 
    } 

    void setShadowSize(float shadowSize, float maxShadowSize) { 
     if (shadowSize < 0 || maxShadowSize < 0) { 
      throw new IllegalArgumentException("invalid shadow size"); 
     } 
     shadowSize = toEven(shadowSize); 
     maxShadowSize = toEven(maxShadowSize); 
     if (shadowSize > maxShadowSize) { 
      shadowSize = maxShadowSize; 
      if (!mPrintedShadowClipWarning) { 
       mPrintedShadowClipWarning = true; 
      } 
     } 
     if (mRawShadowSize == shadowSize && mRawMaxShadowSize == maxShadowSize) { 
      return; 
     } 
     mRawShadowSize = shadowSize; 
     mRawMaxShadowSize = maxShadowSize; 
     mShadowSize = (int)(shadowSize * SHADOW_MULTIPLIER + mInsetShadow + .5f); 
     mMaxShadowSize = maxShadowSize + mInsetShadow; 
     mDirty = true; 
     invalidateSelf(); 
    } 

    @Override 
    public boolean getPadding(Rect padding) { 
     int vOffset = (int) Math.ceil(calculateVerticalPadding(mRawMaxShadowSize, mCornerRadius, 
       mAddPaddingForCorners)); 
//  int hOffset = (int) Math.ceil(calculateHorizontalPadding(mRawMaxShadowSize, mCornerRadius, 
//    mAddPaddingForCorners)); 
//  padding.set(hOffset, vOffset, hOffset, vOffset); 
     padding.set(0, vOffset, 0, 0); 
     return true; 
    } 

    static float calculateVerticalPadding(float maxShadowSize, float cornerRadius, 
              boolean addPaddingForCorners) { 
     if (addPaddingForCorners) { 
      return (float) (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius); 
     } else { 
      return maxShadowSize * SHADOW_MULTIPLIER; 
     } 
    } 

    static float calculateHorizontalPadding(float maxShadowSize, float cornerRadius, 
              boolean addPaddingForCorners) { 
     if (addPaddingForCorners) { 
      return (float) (maxShadowSize + (1 - COS_45) * cornerRadius); 
     } else { 
      return maxShadowSize; 
     } 
    } 

    @Override 
    public void setColorFilter(ColorFilter cf) { 
     mPaint.setColorFilter(cf); 
     mCornerShadowPaint.setColorFilter(cf); 
     mEdgeShadowPaint.setColorFilter(cf); 
    } 

    @Override 
    public int getOpacity() { 
     return PixelFormat.TRANSLUCENT; 
    } 

    void setCornerRadius(float radius) { 
     radius = (int) (radius + .5f); 
     if (mCornerRadius == radius) { 
      return; 
     } 
     mCornerRadius = radius; 
     mDirty = true; 
     invalidateSelf(); 
    } 

    @Override 
    public void draw(Canvas canvas) { 
     if (mDirty) { 
      buildComponents(getBounds()); 
      mDirty = false; 
     } 
     canvas.translate(0, -mRawShadowSize/2); 
     drawShadow(canvas); 
     canvas.translate(0, +mRawShadowSize/2); 
     sRoundRectHelper.drawRoundRect(canvas, mCardBounds, mCornerRadius, mPaint); 
    } 

    private void drawShadow(Canvas canvas) { 
     final float edgeShadowTop = -mCornerRadius - mShadowSize; 
     final float insetVertical = mCornerRadius + mInsetShadow + mRawShadowSize/2; 
     final float insetHorizontal = -mInsetShadow; 
     // LT top 
     int saved = canvas.save(); 
     canvas.translate(mCardBounds.left + insetHorizontal, mCardBounds.top + insetVertical); 
     canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 
     canvas.drawRect(0, edgeShadowTop, 
       mCardBounds.width() - 2 * insetHorizontal, -mCornerRadius + mShadowSize, 
       mEdgeShadowPaint); 
     canvas.restoreToCount(saved); 

     // RT right 
     saved = canvas.save(); 
     canvas.translate(mCardBounds.right - insetHorizontal, mCardBounds.top + insetVertical); 
     canvas.rotate(90f); 
     canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); 
     canvas.restoreToCount(saved); 
    } 

    private void buildShadowCorners() { 
     RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius); 
     RectF outerBounds = new RectF(innerBounds); 
     outerBounds.inset(-mShadowSize, -mShadowSize); 

     if (mCornerShadowPath == null) { 
      mCornerShadowPath = new Path(); 
     } else { 
      mCornerShadowPath.reset(); 
     } 
     mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD); 
     mCornerShadowPath.moveTo(-mCornerRadius, 0); 
     mCornerShadowPath.rLineTo(-mShadowSize, 0); 
     // outer arc 
     mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false); 
     // inner arc 
     mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false); 
     mCornerShadowPath.close(); 
     float startRatio = mCornerRadius/(mCornerRadius + mShadowSize); 
     mCornerShadowPaint.setShader(new RadialGradient(0, 0, mCornerRadius + mShadowSize, 
       new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, 
       new float[]{0f, startRatio, 1f} 
       , Shader.TileMode.CLAMP)); 

     // we offset the content shadowSize/2 pixels up to make it more realistic. 
     // this is why edge shadow shader has some extra space 
     // When drawing bottom edge shadow, we use that extra space. 
     mEdgeShadowPaint.setShader(new LinearGradient(0, -mCornerRadius + mShadowSize, 0, 
       -mCornerRadius - mShadowSize, 
       new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, 
       new float[]{0f, .5f, 1f}, Shader.TileMode.CLAMP)); 
     mEdgeShadowPaint.setAntiAlias(false); 
    } 

    private void buildComponents(Rect bounds) { 
     // Card is offset SHADOW_MULTIPLIER * maxShadowSize to account for the shadow shift. 
     // We could have different top-bottom offsets to avoid extra gap above but in that case 
     // center aligning Views inside the CardView would be problematic. 
     final float verticalOffset = mRawMaxShadowSize * SHADOW_MULTIPLIER; 
     mCardBounds.set(bounds.left + mRawMaxShadowSize, bounds.top + verticalOffset, 
       bounds.right - mRawMaxShadowSize, bounds.bottom - verticalOffset); 
     buildShadowCorners(); 
    } 

    float getCornerRadius() { 
     return mCornerRadius; 
    } 

    void getMaxShadowAndCornerPadding(Rect into) { 
     getPadding(into); 
    } 

    void setShadowSize(float size) { 
     setShadowSize(size, mRawMaxShadowSize); 
    } 

    void setMaxShadowSize(float size) { 
     setShadowSize(mRawShadowSize, size); 
    } 

    float getShadowSize() { 
     return mRawShadowSize; 
    } 

    float getMaxShadowSize() { 
     return mRawMaxShadowSize; 
    } 

    float getMinWidth() { 
     final float content = 2 * 
       Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + mRawMaxShadowSize/2); 
     return content + (mRawMaxShadowSize + mInsetShadow) * 2; 
    } 

    float getMinHeight() { 
     final float content = 2 * Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow 
       + mRawMaxShadowSize * SHADOW_MULTIPLIER/2); 
     return content + (mRawMaxShadowSize * SHADOW_MULTIPLIER + mInsetShadow) * 2; 
    } 

    public void setColor(int color) { 
     mPaint.setColor(color); 
     invalidateSelf(); 
    } 

    static interface RoundRectHelper { 
     void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, Paint paint); 
    } 
} 

ответ

0

Таким образом, проблема в том, что я рисую прямоугольник Ове всего представления. Прямоугольник должен быть нарисован на отдельном изображении, посвященном теневому эффекту.

Кроме того, теневой вид должен иметь высоту не более 6dp или прямоугольник будет показывать, если это имеет смысл.

последнее замечание, используйте эти значения плотности и высоты

float elevation = 2; 
float density = getResources().getDisplayMetrics().density; 

Вот мой макет

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context="info.androidhive.materialtabs.fragments.OneFragment"> 

    <TextView 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:text="This Is A Fragment" 
     android:gravity="center" 
     android:textSize="40dp" 
     android:textStyle="bold" 
     android:layout_centerInParent="true" 
     android:layout_above="@+id/bottomView"/> 


    <View 
     android:id="@+id/bottomView" 
     android:layout_width="match_parent" 
     android:layout_height="6dp" 
     android:layout_above="@+id/other"/> 

    <View 
     android:id="@id/other" 
     android:layout_alignParentBottom="true" 
     android:layout_width="match_parent" 
     android:layout_height="175dp" 
     android:background="?attr/colorPrimary"/> 

</RelativeLayout> 
+1

Плотность зависит от устройства, вы должны использовать эту функцию: плотность поплавка = GetResources(). . getDisplayMetrics() плотность; – mdiener

+0

Может быть, это просто впечатление, но тень выглядит немного темнее теней ленты. –