AndroidTV开发4实现View的焦点带阴影效果

一、Android中实现View的阴影效果有以下四种方法:

1.使用系统自带的CardView.

2.使用shape多层次颜色渐变实现.

3.找UI切一张带阴影效果的图.

4.自定义View实现阴影效果.

二、各种方式的代码如下:

1.使用CardView:

<androidx.cardview.widget.CardView
    android:id="@+id/cardview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:layout_margin="20dp"
    card:cardCornerRadius="4dp"
    card:cardElevation="10dp"
    card:cardMaxElevation="10dp"
    app:layout_constraintTop_toBottomOf="@+id/rl_image"
    tools:ignore="MissingConstraints">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="黄鹤楼\n昔人已乘黄鹤去,此地空余黄鹤楼。\n黄鹤一去不复返,白云千载空悠悠。\n晴川历历汉阳树,芳草萋萋鹦鹉洲。\n日暮乡关何处是?烟波江上使人愁。" />
</androidx.cardview.widget.CardView>

2.使用shape方式:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#8003DAC5" />
            <corners android:radius="10dp" />
        </shape>
    </item>
    <item android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp">
        <shape android:shape="rectangle">
            <solid android:color="#6003DAC5" />
            <corners android:radius="8dp" />
        </shape>
    </item>
    <item
        android:bottom="5dp"
        android:left="5dp"
        android:right="5dp"
        android:top="5dp">
        <shape
            android:layout_width="wrap_content"
            android:shape="rectangle">
            <stroke
                android:width="1dp"
                android:color="#03DAC5" />
        </shape>
    </item>
    <item
        android:bottom="6dp"
        android:left="6dp"
        android:right="6dp"
        android:top="6dp">
        <shape android:shape="rectangle">
            <stroke
                android:width="1dp"
                android:color="#03DAC5" />
        </shape>
    </item>
    <item
        android:bottom="6dp"
        android:left="6dp"
        android:right="6dp"
        android:top="6dp">
        <shape android:shape="rectangle">
            <stroke
                android:width="1dp"
                android:color="#03DAC5" />
        </shape>
    </item>
    <item
        android:bottom="7dp"
        android:left="7dp"
        android:right="7dp"
        android:top="7dp">
        <color android:color="#141843"/>
    </item>
</layer-list>
     

3.ui切图很简单就是一张图片这里就不写了 .

4.自定义view实现阴影效果:

package com.example.focusimageview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

/**
 * @author: njb
 * @date: 2020/7/2 0002 0:08
 * @desc:
 */

public class ShadowLayerView extends ViewGroup {

    private final float deltaLength;
    private final float cornerRadius;
    private final Paint mShadowPaint;
    private boolean drawShadow;

    public ShadowLayerView(Context context) {
        this(context, null);
    }

    public ShadowLayerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ShadowLayerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ShadowLayerView);
        int shadowColor = a.getColor(R.styleable.ShadowLayerView_containerShadowColor, Color.RED);
//        int shadowColor = Color.RED;
        float shadowRadius = a.getDimension(R.styleable.ShadowLayerView_containerShadowRadius, 0);
        deltaLength = a.getDimension(R.styleable.ShadowLayerView_containerDeltaLength, 0);
        cornerRadius = a.getDimension(R.styleable.ShadowLayerView_containerCornerRadius, 0);
        float dx = a.getDimension(R.styleable.ShadowLayerView_deltaX, 0);
        float dy = a.getDimension(R.styleable.ShadowLayerView_deltaY, 0);
        drawShadow = a.getBoolean(R.styleable.ShadowLayerView_enable, true);
        a.recycle();
        mShadowPaint = new Paint();
        mShadowPaint.setStyle(Paint.Style.FILL);
        mShadowPaint.setAntiAlias(true);
        mShadowPaint.setColor(shadowColor);
        mShadowPaint.setShadowLayer(shadowRadius, dx, dy, shadowColor);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (drawShadow) {
            if (getLayerType() != LAYER_TYPE_SOFTWARE) {
                setLayerType(LAYER_TYPE_SOFTWARE, null);
            }
            View child = getChildAt(0);
            int left = child.getLeft();
            int top = child.getTop();
            int right = child.getRight();
            int bottom = child.getBottom();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius, mShadowPaint);
            } else {
                Path drawablePath = new Path();
                drawablePath.moveTo(left + cornerRadius, top);
                drawablePath.arcTo(new RectF(left, top, left + 2 * cornerRadius, top + 2 * cornerRadius), -90, -90, false);
                drawablePath.lineTo(left, bottom - cornerRadius);
                drawablePath.arcTo(new RectF(left, bottom - 2 * cornerRadius, left + 2 * cornerRadius, bottom), 180, -90, false);
                drawablePath.lineTo(right - cornerRadius, bottom);
                drawablePath.arcTo(new RectF(right - 2 * cornerRadius, bottom - 2 * cornerRadius, right, bottom), 90, -90, false);
                drawablePath.lineTo(right, top + cornerRadius);
                drawablePath.arcTo(new RectF(right - 2 * cornerRadius, top, right, top + 2 * cornerRadius), 0, -90, false);
                drawablePath.close();
                canvas.drawPath(drawablePath, mShadowPaint);
            }
        }
        super.dispatchDraw(canvas);
    }

    public void setDrawShadow(boolean drawShadow){
        if (this.drawShadow == drawShadow){
            return;
        }
        this.drawShadow = drawShadow;
        postInvalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (getChildCount() != 1) {
            throw new IllegalStateException("子View只能有一个");
        }
        int measuredWidth = getMeasuredWidth();
        int measuredHeight = getMeasuredHeight();
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        View child = getChildAt(0);
        LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
        int childBottomMargin = (int) (Math.max(deltaLength, layoutParams.bottomMargin) + 1);
        int childLeftMargin = (int) (Math.max(deltaLength, layoutParams.leftMargin) + 1);
        int childRightMargin = (int) (Math.max(deltaLength, layoutParams.rightMargin) + 1);
        int childTopMargin = (int) (Math.max(deltaLength, layoutParams.topMargin) + 1);
        int widthMeasureSpecMode;
        int widthMeasureSpecSize;
        int heightMeasureSpecMode;
        int heightMeasureSpecSize;
        if (widthMode == MeasureSpec.UNSPECIFIED){
            widthMeasureSpecMode = MeasureSpec.UNSPECIFIED;
            widthMeasureSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        }else {
            if (layoutParams.width == LayoutParams.MATCH_PARENT) {
                widthMeasureSpecMode = MeasureSpec.EXACTLY;
                widthMeasureSpecSize = measuredWidth - childLeftMargin - childRightMargin;
            } else if (LayoutParams.WRAP_CONTENT == layoutParams.width) {
                widthMeasureSpecMode = MeasureSpec.AT_MOST;
                widthMeasureSpecSize = measuredWidth - childLeftMargin - childRightMargin;
            } else {
                widthMeasureSpecMode = MeasureSpec.EXACTLY;
                widthMeasureSpecSize = layoutParams.width;
            }
        }
        if (heightMode == MeasureSpec.UNSPECIFIED){
            heightMeasureSpecMode = MeasureSpec.UNSPECIFIED;
            heightMeasureSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        }else {
            if (layoutParams.height == LayoutParams.MATCH_PARENT) {
                heightMeasureSpecMode = MeasureSpec.EXACTLY;
                heightMeasureSpecSize = measuredHeight - childBottomMargin - childTopMargin;
            } else if (LayoutParams.WRAP_CONTENT == layoutParams.height) {
                heightMeasureSpecMode = MeasureSpec.AT_MOST;
                heightMeasureSpecSize = measuredHeight - childBottomMargin - childTopMargin;
            } else {
                heightMeasureSpecMode = MeasureSpec.EXACTLY;
                heightMeasureSpecSize = layoutParams.height;
            }
        }
        measureChild(child, MeasureSpec.makeMeasureSpec(widthMeasureSpecSize, widthMeasureSpecMode), MeasureSpec.makeMeasureSpec(heightMeasureSpecSize, heightMeasureSpecMode));
        int parentWidthMeasureSpec = MeasureSpec.getMode(widthMeasureSpec);
        int parentHeightMeasureSpec = MeasureSpec.getMode(heightMeasureSpec);
        int height = measuredHeight;
        int width = measuredWidth;
        int childHeight = child.getMeasuredHeight();
        int childWidth = child.getMeasuredWidth();
        if (parentHeightMeasureSpec == MeasureSpec.AT_MOST){
            height = childHeight + childTopMargin + childBottomMargin;
        }
        if (parentWidthMeasureSpec == MeasureSpec.AT_MOST){
            width = childWidth + childRightMargin + childLeftMargin;
        }
        if (width < childWidth + 2 * deltaLength){
            width = (int) (childWidth + 2 * deltaLength);
        }
        if (height < childHeight + 2 * deltaLength){
            height = (int) (childHeight + 2 * deltaLength);
        }
        if (height != measuredHeight || width != measuredWidth){
            setMeasuredDimension(width, height);
        }
    }

    static class LayoutParams extends MarginLayoutParams{

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }
    }

    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new LayoutParams(p);
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        View child = getChildAt(0);
        int measuredWidth = getMeasuredWidth();
        int measuredHeight = getMeasuredHeight();
        int childMeasureWidth = child.getMeasuredWidth();
        int childMeasureHeight = child.getMeasuredHeight();
        child.layout((measuredWidth - childMeasureWidth) / 2, (measuredHeight - childMeasureHeight) / 2, (measuredWidth + childMeasureWidth) / 2, (measuredHeight + childMeasureHeight) / 2);
    }


}
三、以上是各种方式的实现代码:1.CardView实现简单,但是颜色不能自定义,2.shape层级方式也很简单,颜色也可以自定义,但是实现的效果不是很满意,3.ui切图方式效果很好,4.自定义view扩展性高。你以为这样就完了吗?NO!NO!NO!小伙子!你还是太天真了!CardView、自定义view方式都不能满足我的焦点阴影效果,因为我目前是开发TV项目,响应的是焦点事件,自定义view和CardView都只能实现单纯的阴影效果,焦点效果我尝试了没反应,于是结合上一篇也是用一个父布局嵌套一个图片,来设置焦点阴影效果,具体代码如下:
<RelativeLayout
    android:id="@+id/rl_update"
    android:layout_width="88dp"
    android:layout_height="100dp"
    android:layout_marginTop="10dp"
    android:background="@drawable/bg_recyclerview_item"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:focusable="true"
    android:focusableInTouchMode="true"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/cardview">

    <ImageView
        android:id="@+id/iv_update"
        android:layout_width="76dp"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:scaleType="fitCenter"
        android:src="@mipmap/ic_version_update" />
</RelativeLayout>

四、完整的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:card="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:background="@drawable/shape_vip_select_bg"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:gravity="center"
        android:text="文本"
        android:textColor="@color/colorPrimary"
        app:layout_constraintLeft_toRightOf="parent"
        app:layout_constraintRight_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:layout_marginTop="20dp"
        android:background="@drawable/shape_vip_select_bg"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:gravity="center"
        android:text="按钮"
        android:textColor="@color/colorPrimary"
        app:layout_constraintLeft_toRightOf="parent"
        app:layout_constraintRight_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <RelativeLayout
        android:id="@+id/rl_image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginTop="20dp"
        android:background="@drawable/shape_vip_select_bg"
        android:focusable="true"
        android:focusableInTouchMode="true"
        app:layout_constraintLeft_toRightOf="parent"
        app:layout_constraintRight_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button">

        <ImageView
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:layout_centerInParent="true"
            android:scaleType="fitXY"
            android:src="@mipmap/index_play_3" />
    </RelativeLayout>

    <androidx.cardview.widget.CardView
        android:id="@+id/cardview"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_margin="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/rl_image"
        card:cardCornerRadius="4dp"
        card:cardElevation="10dp"
        card:cardMaxElevation="10dp"
        tools:ignore="MissingConstraints">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:layout_gravity="center"
            android:gravity="center"
            android:text="黄鹤楼\n昔人已乘黄鹤去,此地空余黄鹤楼。\n黄鹤一去不复返,白云千载空悠悠。\n晴川历历汉阳树,芳草萋萋鹦鹉洲。\n日暮乡关何处是?烟波江上使人愁。" />
    </androidx.cardview.widget.CardView>

    <RelativeLayout
        android:id="@+id/rl_update"
        android:layout_width="88dp"
        android:layout_height="100dp"
        android:layout_marginTop="10dp"
        android:background="@drawable/bg_recyclerview_item"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:focusable="true"
        android:focusableInTouchMode="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/cardview">

        <ImageView
            android:id="@+id/iv_update"
            android:layout_width="76dp"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:scaleType="fitCenter"
            android:src="@mipmap/ic_version_update" />
    </RelativeLayout>

    <com.example.focusimageview.ShadowLayerView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginStart="80dp"
        android:layout_marginTop="50dp"
        app:containerCornerRadius="5dp"
        app:containerDeltaLength="5dp"
        app:containerShadowColor="@color/color_f6d8b9"
        app:containerShadowRadius="5dp"
        app:layout_constraintLeft_toRightOf="@id/rl_image"
        tools:ignore="MissingConstraints">

        <View
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="@color/white" />

    </com.example.focusimageview.ShadowLayerView>


</androidx.constraintlayout.widget.ConstraintLayout>

最后,放一张完整的各种实现方式效果截图:

总结一下:可能实现方式不是很好,但是总算是实现了,关于图片实现阴影效果切图还算比较好之外,上一篇只能算完成任务,目前没有找到更好的解决方法,关于view的阴影和焦点阴影效果还是有区别的,如果小伙伴们有更好的方式,可以提出来,我会及时更正,学习好的方法和经验,不断成长.

例子的源码地址如下:smile drily/ImagViewFocus

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值