美文网首页Android开发
android tv 焦点移动控件-飞框-FlowView

android tv 焦点移动控件-飞框-FlowView

作者: ihu11 | 来源:发表于2019-10-16 15:38 被阅读0次

    github库---demo源码-https://github.com/ihu11/MetroRecyclerView

    1.先来一张效果图展示焦点移动控制

    device-2019-10-16-145843.gif device-2019-10-16-145301.gif

    功能概述
    1、焦点框独立于整个界面之上,可以与直接与其他控件和view的交互,且自己管理自己的绘制线程,所以焦点框可以在屏幕的任意位置上移动,不局限于当前的列表控件。也方便了统一的管理
    2、主要实现了焦点框的平滑移动,只需要知道下一个焦点的view就可以根据这个view的位置把焦点框移动过去。
    3、在移动过程中,如果选择了其他焦点,该焦点框会根据下一个焦点的位置自动转移方向,不需要等下上一次的焦点事件完成,可以时刻响应焦点移动事件的改变。
    4、不管下一个焦点与当前焦点的大小是否一样,焦点框都是准确到框住下一个焦点的区域,焦点框的大小根据焦点位置和区域的大小自动改变。
    5、焦点框的资源图片也可以动态改变,适应不同需求的焦点框,例如从圆角的方框移动到一个直角的方框上,通过切换焦点框的资源图而改变形状。
    6、开放可重载方法,提供其他类继承,可在该控件上再定制其他效果,例如在焦点框上增加动画效果
    7、焦点框直接绘制不需要地图,可以变换为任意颜色和形状

    流程图

    代码实现

    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.view.ViewTreeObserver;
    import android.widget.TextView;
    
    import com.ihu11.metro.flow.FlowNormalView;
    import com.ihu11.metro.flow.FlowView;
    
    public class MainActivity extends Activity implements View.OnFocusChangeListener, View.OnClickListener {
        private FlowView flowView;
        private TextView textView1;
        private TextView textView2;
        private TextView textView3;
        private TextView textView4;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            flowView = findViewById(R.id.flow_view);
            textView1 = findViewById(R.id.text1);
            textView2 = findViewById(R.id.text2);
            textView3 = findViewById(R.id.text3);
            textView4 = findViewById(R.id.text4);
            textView1.setOnFocusChangeListener(this);
            textView2.setOnFocusChangeListener(this);
            textView3.setOnFocusChangeListener(this);
            textView4.setOnFocusChangeListener(this);
            textView1.setOnClickListener(this);
            textView2.setOnClickListener(this);
            textView3.setOnClickListener(this);
            textView4.setOnClickListener(this);
    
            textView4.setNextFocusDownId(R.id.text1);
            textView1.setNextFocusUpId(R.id.text4);
    
            requestViewFocus(textView1);
        }
    
        @Override
        public void onFocusChange(View view, boolean b) {
            if (b) {
                if (view == textView1) {
                    //flowView.setSmooth(false);//直接到 不使用动画
                } else if (view == textView2) {
                    flowView.setFlowPadding(20, 20, 20, 20);//增加边框距离
                } else if (view == textView3) {
                    flowView.setNextShape(FlowNormalView.SHAPE_RECT);//变成直角方形
                } else if (view == textView4) {
                    flowView.setNextShape(FlowNormalView.SHAPE_ROUND);//变成圆边方形
                }
                flowView.moveTo(view, 1.0f);
            }
        }
    
        public static void requestViewFocus(final View view) {
            if (view.getWidth() > 0 && view.getHeight() > 0) {
                view.requestFocus();
                return;
            }
            view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    
                @SuppressWarnings("deprecation")
                @Override
                public void onGlobalLayout() {
                    int width = view.getWidth();
                    int height = view.getHeight();
                    if (width > 0 && height > 0) {
                        view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        view.setFocusable(true);
                        view.requestFocus();
                    }
                }
            });
        }
    
        @Override
        public void onClick(View view) {
            if (view == textView3) {
                startActivity(new Intent(this, GridActivity.class));
            } else if (view == textView2) {
                startActivity(new Intent(this, HorActivity.class));
            } else if (view == textView1) {
                startActivity(new Intent(this, VerActivity.class));
            } else if (view == textView4) {
                startActivity(new Intent(this, ModifyActivity.class));
            }
        }
    }
    
    

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffB0C4DE">
    
        <TextView
            android:id="@+id/text1"
            android:layout_width="100px"
            android:layout_height="50px"
            android:layout_marginLeft="200px"
            android:layout_marginTop="200px"
            android:focusable="true"
            android:gravity="center"
            android:text="垂直列表"
            android:textColor="#ffffffff" />
    
        <TextView
            android:id="@+id/text2"
            android:layout_width="110px"
            android:layout_height="50px"
            android:layout_marginLeft="200px"
            android:layout_marginTop="300px"
            android:focusable="true"
            android:gravity="center"
            android:text="水平列表"
            android:textColor="#ffffffff" />
    
        <TextView
            android:id="@+id/text3"
            android:layout_width="120px"
            android:layout_height="50px"
            android:layout_marginLeft="200px"
            android:layout_marginTop="400px"
            android:focusable="true"
            android:gravity="center"
            android:text="网格列表"
            android:textColor="#ffffffff" />
    
        <TextView
            android:id="@+id/text4"
            android:layout_width="160px"
            android:layout_height="50px"
            android:layout_marginLeft="200px"
            android:layout_marginTop="500px"
            android:focusable="true"
            android:gravity="center"
            android:text="可删除项的列表"
            android:textColor="#ffffffff" />
    
        <com.ihu11.metro.flow.FlowView
            android:id="@+id/flow_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:flow_color1="@android:color/white"
            app:flow_color2="@android:color/black"
            app:viewType="normal"
            app:flow_stroke_width="2px"
            app:round_radius="5px" />
    
    </RelativeLayout>
    

    FlowView

    package com.ihu11.metro.flow;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.util.AttributeSet;
    import android.view.View;
    import android.view.ViewGroup;
    
    import com.ihu11.metro.R;
    
    public class FlowView extends ViewGroup {
    
        public final static int VIEW_TYPE_NORMAL = 0;
        public final static int VIEW_TYPE_SOLID = 1;
        public final static int VIEW_TYPE_NO_SHADOW = 2;
    
        protected FlowNormalView iFlowView;
        private int viewType;
        private float roundRadius;
    
        public FlowView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs);
        }
    
        public FlowView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public FlowView(Context context) {
            this(context, null);
        }
    
        private void init(Context context, AttributeSet attrs) {
            int color1 = -1;
            int color2 = -1;
            int strokeWidth = -1;
            if (attrs != null) {
                TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowView);
                viewType = a.getInt(R.styleable.FlowView_viewType, VIEW_TYPE_NORMAL);
                roundRadius = a.getDimensionPixelSize(R.styleable.FlowView_round_radius, 0);
                color1 = a.getResourceId(R.styleable.FlowView_flow_color1, -1);
                color2 = a.getResourceId(R.styleable.FlowView_flow_color2, -1);
                strokeWidth = a.getResourceId(R.styleable.FlowView_flow_stroke_width, -1);
                a.recycle();
            } else {
                viewType = VIEW_TYPE_NORMAL;
            }
    
            if (viewType == VIEW_TYPE_NORMAL) {
                iFlowView = new FlowNormalView(context);
                addView(iFlowView);
            } else if (viewType == VIEW_TYPE_SOLID) {
                iFlowView = new FlowSolidView(context);
                addView(iFlowView);
            } else if (viewType == VIEW_TYPE_NO_SHADOW) {
                iFlowView = new FlowNormalView(context);
                iFlowView.setNoShawdow();
                addView(iFlowView);
            }
    
            iFlowView.setDefaultRadius(roundRadius);
            iFlowView.setStrokeWidth(strokeWidth);
            int c1 = -1;
            if (color1 != -1) {
                c1 = getResources().getColor(color1);
            }
            int c2 = -1;
            if (color2 != -1) {
                c2 = getResources().getColor(color2);
            }
            iFlowView.setRectColor(c1, c2);
        }
    
        @Override
        public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
            return new MarginLayoutParams(getContext(), attrs);
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            int cCount = getChildCount();
            for (int i = 0; i < cCount; i++) {
                View childView = getChildAt(i);
                childView.layout(l, t, r, b);
            }
        }
    
        @Override
        public void setVisibility(int visibility) {
            super.setVisibility(visibility);
            int cCount = getChildCount();
            for (int i = 0; i < cCount; i++) {
                View childView = getChildAt(i);
                childView.setVisibility(visibility);
            }
        }
    
        public void moveTo(View view, float scale) {
            if (iFlowView != null) {
                iFlowView.moveTo(view, scale);
            }
        }
    
        public void setFlowPadding(int left, int top, int right, int bottom) {
            if (iFlowView != null) {
                iFlowView.setFlowPadding(left, top, right, bottom);
            }
        }
    
        public void moveTo(float x, float y, float width, float height, float scale) {
            if (iFlowView != null) {
                iFlowView.moveTo(x, y, width, height, scale);
            }
        }
    
        public void moveTo(View view, float scale, int offsetX, int offsetY, boolean isSmooth) {
            if (iFlowView != null) {
                iFlowView.moveTo(view, scale, offsetX, offsetY, isSmooth);
            }
        }
    
        public void setOffset(int x, int y) {
            if (iFlowView != null) {
                iFlowView.setOffset(x, y);
            }
        }
    
        public void setSmooth(boolean isSmooth) {
            if (iFlowView != null) {
                iFlowView.setSmooth(isSmooth);
            }
        }
    
        public void setNextShape(int shape) {
            if (iFlowView != null) {
                iFlowView.setNextShape(shape);
            }
        }
    
        public void setRectColor(int rectColor, int shadowColor) {
            if (iFlowView != null) {
                iFlowView.setRectColor(rectColor, shadowColor);
            }
        }
    
        public void setStrokeWidth(float strokeWidth) {
            iFlowView.setStrokeWidth(strokeWidth);
        }
    
        public void setDefaultRadius(float roundRadius) {
            iFlowView.setDefaultRadius(roundRadius);
        }
    }
    

    FlowNormalView

    package com.ihu11.metro.flow;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.RectF;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.animation.AccelerateDecelerateInterpolator;
    import android.view.animation.AccelerateInterpolator;
    import android.view.animation.DecelerateInterpolator;
    import android.view.animation.Interpolator;
    
    public class FlowNormalView extends View {
    
        public final static int SHAPE_ROUND_RECT = 0;
        public final static int SHAPE_RECT = 1;
        public final static int SHAPE_ROUND = 2;
    
        private final static String TAG = "FlowHand";
        private final static float SPEED = 2f;// 默认速度
        private final static long MIN_FLOW_TIME = 200;// 最小时间
        private final static long MAX_FLOW_TIME = 300;// 最大时间
        private final static float SHADOW_TOTAL_WIDTH = 40f;
        private final static float SHADOW_STROKE_WIDTH = 1f;
        private final static int SHADOW_ALPHA_START = 150;
        private static final Interpolator mInterpolator1 = new AccelerateDecelerateInterpolator();
        private static final Interpolator mInterpolator2 = new DecelerateInterpolator();
        private static final Interpolator mInterpolatorShadow = new AccelerateInterpolator();
        private static final int INTERVAL_TIME_NORMAL = 20;
    
        private boolean isRun = false;
        private int offsetX = 0;
        private int offsetY = 0;
        private int paddingLeft = 0;
        private int paddingRight = 0;
        private int paddingTop = 0;
        private int paddingBottom = 0;
        private int shape = SHAPE_ROUND_RECT;
        private float strokeWidth;
        protected float screenScale;
        private boolean isSmooth = true;
        private boolean isContinuityMove = false;
        private boolean noShawdow = false;
    
        private int rectColor = 0xFFFFFFFF;
        private int shadowColor = 0xFF000000;
    
        private RoundRectF lastRectF;
        private RoundRectF currRectF;
        private RoundRectF destRectF;
        private RoundRectF shadowRectF;
    
        protected Paint mPaint;
        private Paint mPaintShadow;
        private Paint paintEraser;
        private float defaultRadius;
    
        private long startTime = 0L;
        private long totalTime = 0L;
        private float distance = 0f;
    
        class RoundRectF extends RectF {
            float radius;
    
            public RoundRectF() {
            }
    
            public void set(RoundRectF src) {
                this.left = src.left;
                this.right = src.right;
                this.top = src.top;
                this.bottom = src.bottom;
                this.radius = src.radius;
            }
    
        }
    
        public FlowNormalView(Context context) {
            super(context);
            init(context);
        }
    
        public FlowNormalView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        public FlowNormalView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
        public FlowNormalView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            init(context);
        }
    
        protected void init(Context context) {
    
            lastRectF = new RoundRectF();
            currRectF = new RoundRectF();
            destRectF = new RoundRectF();
            shadowRectF = new RoundRectF();
    
            screenScale = context.getResources().getDisplayMetrics().widthPixels / 1920f;
            strokeWidth = 2f * screenScale;
    
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setColor(rectColor);
            mPaint.setStrokeWidth(strokeWidth);
            mPaint.setStyle(Paint.Style.STROKE);
    
            mPaintShadow = new Paint();
            mPaintShadow.setAntiAlias(true);
            mPaintShadow.setColor(shadowColor);
            mPaintShadow.setStyle(Paint.Style.STROKE);
    
            paintEraser = new Paint();
            paintEraser.setAntiAlias(true);
            paintEraser.setColor(Color.BLACK);
            paintEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        }
    
        private void start() {
            if (isRun) {
                return;
            }
            isRun = true;
            new Thread() {
                public void run() {
                    while (isRun) {
                        refreshView();
                    }
                    isRun = false;
                }
            }.start();
        }
    
        protected void refreshView() {
            try {
                Thread.sleep(INTERVAL_TIME_NORMAL);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            postInvalidate();
        }
    
        protected void moveToLocation(float l, float t, float width, float height, float roundScale) {
            resetLast();
    
            // 偏移量
            l -= offsetX;
            t -= offsetY;
    
            destRectF.left = l - paddingLeft;
            destRectF.right = l + width + paddingRight;
            destRectF.top = t - paddingTop;
            destRectF.bottom = t + height + paddingBottom;
            if (shape == SHAPE_ROUND_RECT) {
                destRectF.radius = defaultRadius * roundScale;
            } else if (shape == SHAPE_RECT) {
                destRectF.radius = 0f;
            } else if (shape == SHAPE_ROUND) {
                destRectF.radius = Math.min(destRectF.bottom - destRectF.top, destRectF.right - destRectF.left) / 2;
            }
    
            startTime = System.currentTimeMillis();
            distance = getDistance(lastRectF.centerX(), lastRectF.centerY(), destRectF.centerX(), destRectF.centerY());
    
            if (isSmooth) {
                if (lastRectF.width() < 0.1f || lastRectF.height() < 0.1f) {
                    totalTime = 0;
                } else {
                    totalTime = (long) (distance / SPEED);
                    if (totalTime > MAX_FLOW_TIME) {
                        totalTime = MAX_FLOW_TIME;
                    } else if (totalTime < MIN_FLOW_TIME) {
                        totalTime = MIN_FLOW_TIME;
                    }
                }
            } else {
                totalTime = 0;
            }
            reset();
            start();
        }
    
        private float getDistance(float x1, float y1, float x2, float y2) {
            return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
        }
    
        private float getCurrDistance() {
            long time = System.currentTimeMillis();
            if (time >= startTime + totalTime) {
                return distance;
            }
            float p = (time - startTime) / (float) totalTime;
            if (isContinuityMove) {
                return mInterpolator2.getInterpolation(p) * distance;
            } else {
                return mInterpolator1.getInterpolation(p) * distance;
            }
        }
    
        private void resetLast() {
            if (Math.abs(getCurrDistance() - distance) < 0.1f) {
                isContinuityMove = false;
            } else {
                isContinuityMove = true;
            }
    
            lastRectF.set(currRectF);
        }
    
        @Override
        public void onDraw(Canvas canvas) {
            drawView(canvas);
        }
    
        private void drawView(Canvas canvas) {
            float currDistance = getCurrDistance();
            if (distance != 0) {
                currRectF.left = lastRectF.left + (destRectF.left - lastRectF.left) * (currDistance / distance);
                currRectF.right = lastRectF.right + (destRectF.right - lastRectF.right) * (currDistance / distance);
                currRectF.top = lastRectF.top + (destRectF.top - lastRectF.top) * (currDistance / distance);
                currRectF.bottom = lastRectF.bottom + (destRectF.bottom - lastRectF.bottom) * (currDistance / distance);
                currRectF.radius = lastRectF.radius + (destRectF.radius - lastRectF.radius) * (currDistance / distance);
            }
    
            if (currRectF.width() > 0.1f && currRectF.height() > 0.1f) {
                drawRoundRectF(canvas, currRectF);
                drawExtra(canvas, currRectF);
            }
    
            if (Math.abs(currDistance - distance) < 0.1f) {
                isContinuityMove = false;
                isRun = false;
            }
        }
    
        protected void drawExtra(Canvas canvas, RectF currRectF) {
    
        }
    
        protected void drawRoundRectF(Canvas canvas, RoundRectF currRectF) {
            shadowRectF.set(currRectF);
            if (!noShawdow) {
                mPaintShadow.setStrokeWidth(SHADOW_STROKE_WIDTH);
                for (float i = 0f; i < SHADOW_TOTAL_WIDTH; i += SHADOW_STROKE_WIDTH) {
                    shadowRectF.left = currRectF.left - i;
                    shadowRectF.top = currRectF.top - i;
                    shadowRectF.right = currRectF.right + i;
                    shadowRectF.bottom = currRectF.bottom + i;
                    shadowRectF.radius = currRectF.radius + i;
                    float p = mInterpolatorShadow.getInterpolation(((SHADOW_TOTAL_WIDTH - i) / SHADOW_TOTAL_WIDTH));
                    mPaintShadow.setAlpha((int) (p * SHADOW_ALPHA_START));
                    canvas.drawRoundRect(shadowRectF, shadowRectF.radius, shadowRectF.radius, mPaintShadow);
                }
            }
            canvas.drawRoundRect(currRectF, currRectF.radius, currRectF.radius, mPaint);
        }
    
        public void setNoShawdow() {
            noShawdow = true;
        }
    
        public void setDefaultRadius(float defaultRadius) {
            this.defaultRadius = defaultRadius;
        }
    
        public void setNextShape(int shape) {
            this.shape = shape;
        }
    
        /**
         * 设置偏移
         *
         * @param x X轴的偏移量
         * @param y Y轴的偏移量
         */
        public void setOffset(int x, int y) {
            offsetX = x;
            offsetY = y;
        }
    
        public void setSmooth(boolean isSmooth) {
            this.isSmooth &= isSmooth;
        }
    
        private void reset() {
            offsetX = 0;
            offsetY = 0;
            isSmooth = true;
            paddingLeft = 0;
            paddingRight = 0;
            paddingTop = 0;
            paddingBottom = 0;
            shape = SHAPE_ROUND_RECT;
        }
    
        /**
         * 移动到view的位置
         *
         * @param view
         * @param scale    是否缩放
         * @param offsetX  X轴的偏移量
         * @param offsetY  Y轴的偏移量
         * @param isSmooth 是否平滑滚动
         */
        public void moveTo(View view, float scale, int offsetX, int offsetY, boolean isSmooth) {
            if (view == null) {
                Log.e(TAG, "view is null");
                return;
            }
            setOffset(offsetX, offsetY);
            setSmooth(isSmooth);
            moveTo(view, scale);
        }
    
        public void moveTo(View view, float scale) {
            int h = view.getHeight();
            int w = view.getWidth();
            // Log.d(TAG, "width:" + w);
            int[] location = new int[2];
            view.getLocationInWindow(location);
            int x = location[0];
            int y = location[1];
    
            x += ((view.getScaleX() - 1) / 2) * w;
            y += ((view.getScaleY() - 1) / 2) * h;
    
            moveTo(x, y, w, h, scale);
        }
    
        public void moveTo(float x, float y, float width, float height, float scale) {
            if (width > 0 && height > 0) {
                int[] location = new int[2];
                ((ViewGroup) getParent().getParent()).getLocationInWindow(location);
                int pX = location[0];
                int pY = location[1];
                float l = x - pX;
                float t = y - pY;
                moveToLocation(l - ((scale - 1) / 2) * width, t - ((scale - 1) / 2) * height, width * scale, height * scale,
                        scale);
            } else {
                reset();
                Log.e(TAG, "width or height is 0");
            }
        }
    
        public void setFlowPadding(int left, int top, int right, int bottom) {
            this.paddingLeft = left;
            this.paddingRight = right;
            this.paddingTop = top;
            this.paddingBottom = bottom;
        }
    
        public void setRectColor(int rectColor, int shadowColor) {
            if (rectColor != -1) {
                this.rectColor = rectColor;
                mPaint.setColor(rectColor);
            }
            if (shadowColor != -1) {
                this.shadowColor = shadowColor;
                mPaintShadow.setColor(shadowColor);
            }
        }
    
        public void setStrokeWidth(float strokeWidth) {
            if (strokeWidth > 0) {
                this.strokeWidth = strokeWidth;
                mPaint.setStrokeWidth(strokeWidth);
            }
        }
    }
    
    

    FlowSolidView

    package com.ihu11.metro.flow;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.LinearGradient;
    import android.graphics.Paint;
    import android.graphics.Shader;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    
    public class FlowSolidView extends FlowNormalView {
    
        private LinearGradient shader;
    
        private int color1;
        private int color2;
    
        public FlowSolidView(Context context) {
            super(context);
        }
    
        public FlowSolidView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        public FlowSolidView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public FlowSolidView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    
        protected void init(Context context) {
            super.init(context);
            mPaint.setStyle(Paint.Style.FILL);
        }
    
        @Override
        public void setRectColor(int color1, int color2) {
            this.color1 = color1;
            this.color2 = color2;
        }
    
        @Override
        protected void drawRoundRectF(Canvas canvas, RoundRectF rectF) {
            if (color1 != color2) {
                shader = new LinearGradient(rectF.left,
                        rectF.top,
                        rectF.right,
                        rectF.top,
                        color1,
                        color2,
                        Shader.TileMode.CLAMP);
                mPaint.setShader(shader);
            } else {
                mPaint.setColor(color1);
            }
    
            canvas.drawRoundRect(rectF, rectF.radius, rectF.radius, mPaint);
        }
    }
    
    

    相关文章

      网友评论

        本文标题:android tv 焦点移动控件-飞框-FlowView

        本文链接:https://www.haomeiwen.com/subject/vxlumctx.html