前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义View学习——粗略实现商品图片内容描述

自定义View学习——粗略实现商品图片内容描述

作者头像
木溪bo
发布2018-12-27 10:18:07
6210
发布2018-12-27 10:18:07
举报

前段时间从朋友那听说一个需求,实现一个商品展示并且添加商品的描述,闲暇时间试着自己实现了一下。 下面看一下效果图:

lufei.gif

当然啦,对于萌新的我只能实现基本功能,与君共勉,还有很多可以优化的地方。下面贴出实现代码,希望可以帮到有需要的兄弟。

自定义属性部分:

代码语言:javascript
复制
   <!--商品图片描述-->
    <declare-styleable name="ImgDescribeView">
        <attr name="imgDescribeBackground" format="reference" /> <!--图片-->
        <attr name="imgContentText" format="string" /> <!--描述内容-->
        <attr name="imgContentTextColor" format="color" /> <!--描述内容颜色-->
        <attr name="imgContentTextSize" format="dimension" /> <!--描述内容字体大小-->
        <attr name="imgLineColor" format="color" /> <!--线颜色-->
        <attr name="imgLineWidth" format="dimension" /> <!--线宽-->
        <attr name="imgLineAngle" format="float" /> <!--线角度-->
        <!--文字方向-->
        <attr name="imgTextForest">
            <enum name="leftToRight" value="0" />
            <enum name="rightToLeft" value="1" />
        </attr>
    </declare-styleable>

XML布局引用:

代码语言:javascript
复制
  <com.fivefloor.bo.myview.widgets.ImgDescribeAnimatorView
        android:id="@+id/img_line"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_200"
        app:imgContentText="现在测试"
        app:imgContentTextColor="@color/colorAccent"
        app:imgContentTextSize="16sp"
        app:imgDescribeBackground="@mipmap/ic_launcher_round"
        app:imgLineAngle="205"
        app:imgLineColor="@color/colorRed"
        app:imgLineWidth="1dp"
        app:imgTextForest="rightToLeft"/>

自定义view:

代码语言:javascript
复制
package com.fivefloor.bo.myview.widgets;

import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import com.fivefloor.bo.myview.R;

/**
 * Author:bobo
 * <p>
 * Create Time:2018/8/15 10:13
 * <p>
 * Email:1245092675@qq.com
 * <p>
 * Describe:动态画线,给图片添加文字说明
 */
public class ImgDescribeAnimatorView extends View {

    /**
     * 小圆心点坐标,整个控件图形以圆心点的圆心坐标为基准绘画
     */
    private float x_CirclePoint_R, y_CirclePoint_R;
    /**
     * 小圆心点半径
     */
    private float CirclePoint_R = 10;
    private Path pathLine;//画线路径
    private Paint paintLine;//画笔
    private int paintLineColor;//画线颜色
    private float angle_a = (float) (Math.PI / 180);//弧度转角度
    private float angle = (float) (angle_a * 205);//角度

    private Paint paintTxt;
    private String textContent;
    /**
     * 图片地址
     */
    private int imgId;
    /**
     * 默认字体大小sp
     */
    private float textSize;
    /**
     * 默认字体颜色
     */
    private int textColor = Color.BLACK;
    /**
     * 线1随动画动态坐标
     */
    private float x_Animator1, y_Animator1;
    /**
     * 线2随动画动态坐标
     */
    private float x_Animator2, y_Animator2;
    /**
     * 位图
     */
    private Bitmap bitmap;
    /**
     * 文字边框,用于得到内容描述的大小属性等
     */
    private Rect rect;
    /**
     * 内容描述渐变显示度
     */
    private float txtProgerss;
    /**
     * 设置开始写字方向,默认从左往右
     */
    private Paint.Align direction = Paint.Align.LEFT;
    /**
     * 线宽
     */
    private float lineWidth = 1;

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

    public ImgDescribeAnimatorView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ImgDescribeAnimatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, 0, 0);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ImgDescribeAnimatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initAttrs(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //因为是圆形图片,所以应该让宽高保持一致
        int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
       //图片宽占控件的1/3
        mWidth = size / 3;
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        x_CirclePoint_R = w / 2;//小圆心点坐标
        y_CirclePoint_R = h / 3;
        initPaint();
    }


    /**
     * 初始化加载设置属性
     */
    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ImgDescribeView);
        //获取商品图片
        int src = typedArray.getResourceId(R.styleable.ImgDescribeView_imgDescribeBackground, R.drawable.icon);
        this.imgId = src;
        //描述内容
        String text = typedArray.getString(R.styleable.ImgDescribeView_imgContentText);
        if (text != null)
            this.textContent = text;
        else
            this.textContent = "通缉路飞";
        //描述内容颜色
        int textcolor = typedArray.getColor(R.styleable.ImgDescribeView_imgContentTextColor, Color.BLACK);
        this.textColor = textcolor;
        //描述内容字体大小
        float textsize = typedArray.getDimensionPixelSize(R.styleable.ImgDescribeView_imgContentTextSize, 12);
        setTextContentSize(textsize);
        //线颜色
        int linecolor = typedArray.getColor(R.styleable.ImgDescribeView_imgLineColor, Color.BLACK);
        this.paintLineColor = linecolor;
        //线宽
        float lineW = typedArray.getDimension(R.styleable.ImgDescribeView_imgLineWidth, 1);
        setLineWidth(lineW);
        //线角度
        float lineangle = typedArray.getFloat(R.styleable.ImgDescribeView_imgLineAngle, 205);
        this.angle = angle_a * lineangle;
        //内容描述动画开始方向
        int textForest = typedArray.getInt(R.styleable.ImgDescribeView_imgTextForest, 0);
        if (textForest == 0) {
            setTextCanvasLeftToRight();
        } else {
            setTextCanvasRightToLeft();
        }
        typedArray.recycle();
    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        paintLine = new Paint();
        paintLine.setAntiAlias(true);
        paintLine.setStrokeCap(Paint.Cap.ROUND);//线帽
        paintLine.setColor(paintLineColor);
        paintLine.setStrokeWidth(lineWidth);//线宽
        paintLine.setTextAlign(Paint.Align.CENTER);
        paintLine.setStyle(Paint.Style.FILL_AND_STROKE);//描边+填充

        pathLine = new Path();
//      获取图片方法1
//        try {
//            InputStream is = getContext().getAssets().open("ic_launcher_round.png");
//            bitmap = BitmapFactory.decodeStream(is);
//            is.close();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        // 获取图片方法2
        bitmap = BitmapFactory.decodeResource(getContext().getResources(), imgId);

        //文本画笔设置及属性
        rect = new Rect();
        paintTxt = new Paint();
        paintTxt.setAntiAlias(true);
        paintTxt.setStyle(Paint.Style.FILL);
        paintTxt.setTextSize(textSize);
        paintTxt.getTextBounds(textContent, 0, textContent.length(), rect);//获得文本框
        initAnimator();
    }


    private void initAnimator() {
        ValueAnimator animatorLine1 = ValueAnimator.ofFloat(0, 100).setDuration(1000);//线1
        ValueAnimator animatorLine2 = ValueAnimator.ofFloat(0, 50).setDuration(1000);//线2
        ValueAnimator animatorTxt = ValueAnimator.ofFloat(0, 1).setDuration(2000);//内容text
        animatorTxt.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //字体
                txtProgerss = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        animatorLine1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //线1
                x_Animator1 = (float) animation.getAnimatedValue();
                y_Animator1 = (float) ((float) animation.getAnimatedValue() * Math.tan(angle));
                invalidate();//刷新ui
            }
        });
        animatorLine2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //线2
                x_Animator2 = (float) animation.getAnimatedValue();
                invalidate();//刷新ui
            }
        });
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(animatorLine1).before(animatorLine2).before(animatorTxt);
        animatorSet.start();
    }

    @SuppressLint("WrongConstant")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawRectImg(canvas);

        paintLine.setStyle(Paint.Style.FILL_AND_STROKE);//描边+填充
        canvas.drawCircle(x_CirclePoint_R, y_CirclePoint_R, CirclePoint_R, paintLine);//画小圆心点
        //------画线1-------
        paintLine.setStyle(Paint.Style.STROKE);//描边
        pathLine.moveTo(x_CirclePoint_R, y_CirclePoint_R);
        pathLine.lineTo(x_CirclePoint_R - x_Animator1, y_CirclePoint_R - y_Animator1);

        if (x_Animator2 != 0) {
            //-------画线2-------
            pathLine.rLineTo(-x_Animator2, 0);//在原有的基础上延伸
        }
        canvas.drawPath(pathLine, paintLine);
        if (txtProgerss != 0) {
            //内容描述
            drawTextContent(canvas);//渐变的内容描述
        }
        paintLine.descent();
        paintTxt.descent();
    }

    /**
     * 画方形图
     * @param canvas
     */
    private void drawRectImg(Canvas canvas) {
        // 指定图片绘制区域,这里设置与图片参数大小一致,绘制完整图片
        Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        // 指定图片在屏幕上显示的区域,大了会缩小,小了会放大
        //开始点位置
        int sX = (int) (x_CirclePoint_R + CirclePoint_R + 10);//+10像素为了美观
        int sY = (int) (y_CirclePoint_R - 2 * CirclePoint_R);
        //缩放比例(宽高缩放比例相同)
        float scale=mWidth/(float)bitmap.getWidth();
        //结束点位置
        int sX2 = (int) (x_CirclePoint_R + CirclePoint_R + mWidth + 10);
        int sY2 = (int) (y_CirclePoint_R - 2 * CirclePoint_R + bitmap.getHeight()*scale);
        Rect dst = new Rect(sX, sY, sX2, sY2);
        // 绘制图片
        canvas.drawBitmap(bitmap, src, dst, null);
    }

    private int mWidth;//图像宽

    @SuppressLint("WrongConstant")
    private void drawTextContent(Canvas canvas) {
        int startX;//裁剪开始位置,结合动画实时刷新实现视觉上的文字渐变效果
        int endX;//裁剪结束位置
        int textLeft = (int) (x_CirclePoint_R - x_Animator1 - x_Animator2 - rect.width());   //文本在控件中的起始x位置
        int textRight = (int) (x_CirclePoint_R - x_Animator1 - x_Animator2);   // 文本在控件中的结束x位置
        float textBottom = y_CirclePoint_R - y_Animator1 + rect.height() / 2;  //文本在控件中的结束y位置
        if (txtProgerss < 0) {
            txtProgerss = 0;
        }
        if (txtProgerss > 1) {
            txtProgerss = 1;
        }
        int changedWidth = (int) ((rect.width() + rect.left) * txtProgerss);
        if (direction == Paint.Align.LEFT) {
            //从左往右显示,裁剪区
            startX = textLeft;
            endX = textLeft + changedWidth;
        } else {
            //从右往左显示,裁剪区
            startX = textRight - changedWidth;
            endX = textRight;
        }
        //画渐变部分的文字
        canvas.save(Canvas.CLIP_SAVE_FLAG);
        paintTxt.setColor(textColor);
        canvas.clipRect(startX, 0, endX, getMeasuredHeight());
        canvas.drawText(textContent, textLeft, textBottom, paintTxt);
        canvas.restore();
    }


    /**
     * 设置描述内容从左往右
     */
    public void setTextCanvasLeftToRight() {
        direction = Paint.Align.LEFT;
        invalidate();
    }

    /**
     * 设置描述内容从右往左
     */
    public void setTextCanvasRightToLeft() {
        direction = Paint.Align.RIGHT;
        invalidate();

    }

    /**
     * 设置内容描述字体大小sp
     */
    public void setTextContentSize(float size) {
        textSize = spToPx(getContext(), size);
    }

    /**
     * 将sp换成px,保证尺寸不变
     *
     * @param context
     * @param spValue
     * @return
     */
    private float spToPx(Context context, float spValue) {
        float scaleDensity = context.getResources().getDisplayMetrics().scaledDensity;
        return (float) (spValue * scaleDensity + 0.5f);
    }

    /**
     * @param lineW 线宽度
     * @return
     */
    public void setLineWidth(float lineW) {
        lineWidth = lineW;
    }

}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.09.07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档