仿淘宝,美团等HOT标签控件 (Button,Textview,Imagview,View)

  来自github的一位国外大神写的,忘了地址,感谢项目里有用到。



直接上代码


xml 配置 字段含义

 app:label_backgroundColor="#C2185B"     标签背景颜色
        app:label_distance="20dp"                      标签距离
        app:label_height="20dp" 标签高度
        app:label_orientation="LEFT_TOP" 标签位置   LEFT_TOP 左上   RIGHT_TOP  右上 LEFT_BOTTOM 左下 RIGHT_BOTTOM  右下
        app:label_text="HD" 标签文字
        app:label_textSize="12sp" 标签字体大小


关键辅助类

LabelViewHelper

package com.textstay;

import com.example.testdemo.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class LabelViewHelper {

    private static final int LEFT_TOP = 1;
    private static final int RIGHT_TOP = 2;
    private static final int LEFT_BOTTOM = 3;
    private static final int RIGHT_BOTTOM = 4;

    private static final int DEFAULT_DISTANCE = 40;
    private static final int DEFAULT_HEIGHT = 20;
    private static final int DEFAULT_TEXT_SIZE = 14;
    private static final int DEFAULT_BACKGROUND_COLOR = 0x9F27CDC0;
    private static final int DEFAULT_TEXT_COLOR = 0xFFFFFFFF;
    private static final int DEFAULT_ORIENTATION = LEFT_TOP;

    private int distance;
    private int height;
    private String text;
    private int backgroundColor;
    private int textSize;
    private int textColor;
    private boolean visual;
    private int orientation;

    private float startPosX;
    private float startPosY;
    private float endPosX;
    private float endPosY;

    private Paint rectPaint;
    // simulator
    private Path rectPath;
    private Paint textPaint;
    private Rect textBound;

    private Context context;
    private int alpha;

    public LabelViewHelper(Context context, AttributeSet attrs, int defStyleAttr) {

        this.context = context;

        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.LabelView, defStyleAttr, 0);
        distance = attributes.getDimensionPixelSize(R.styleable.LabelView_label_distance, dip2Px(DEFAULT_DISTANCE));
        height = attributes.getDimensionPixelSize(R.styleable.LabelView_label_height, dip2Px(DEFAULT_HEIGHT));
        text = attributes.getString(R.styleable.LabelView_label_text);
        backgroundColor = attributes.getColor(R.styleable.LabelView_label_backgroundColor, DEFAULT_BACKGROUND_COLOR);
        textSize = attributes.getDimensionPixelSize(R.styleable.LabelView_label_textSize, dip2Px(DEFAULT_TEXT_SIZE));
        textColor = attributes.getColor(R.styleable.LabelView_label_textColor, DEFAULT_TEXT_COLOR);
        visual = attributes.getBoolean(R.styleable.LabelView_label_visual, true);
        orientation = attributes.getInteger(R.styleable.LabelView_label_orientation, DEFAULT_ORIENTATION);
        attributes.recycle();

        rectPaint = new Paint();
        rectPaint.setDither(true);
        rectPaint.setAntiAlias(true);
        rectPaint.setStyle(Paint.Style.STROKE);
        rectPaint.setStrokeJoin(Paint.Join.ROUND);
        rectPaint.setStrokeCap(Paint.Cap.SQUARE);

        rectPath = new Path();
        rectPath.reset();

        textPaint = new Paint();
        textPaint.setDither(true);
        textPaint.setAntiAlias(true);
        textPaint.setStrokeJoin(Paint.Join.ROUND);
        textPaint.setStrokeCap(Paint.Cap.SQUARE);

        textBound = new Rect();
    }

    public void onDraw(Canvas canvas, int measuredWidth, int measuredHeight) {
        if (!visual || text == null) {
            return;
        }

        float actualDistance = distance + height / 2;
        calcOffset(actualDistance, measuredWidth, measuredHeight);

        rectPaint.setColor(backgroundColor);
        if (alpha != 0) {
            rectPaint.setAlpha(alpha);
        }
        rectPaint.setStrokeWidth(height);

        rectPath.reset();
        rectPath.moveTo(startPosX, startPosY);
        rectPath.lineTo(endPosX, endPosY);
        canvas.drawPath(rectPath, rectPaint);

        textPaint.setTextSize(textSize);
        textPaint.setColor(textColor);
        textPaint.getTextBounds(text, 0, text.length(), textBound);

        float begin_w_offset = (1.4142135f * actualDistance) / 2 - textBound.width() / 2;
        if (begin_w_offset < 0) begin_w_offset = 0;

        canvas.drawTextOnPath(text, rectPath, begin_w_offset, textBound.height() / 2, textPaint);
    }

    private void calcOffset(float actualDistance, int measuredWidth, int measuredHeight) {
        switch (orientation) {
            case 1:
                startPosX = 0;
                startPosY = actualDistance;
                endPosX = actualDistance;
                endPosY = 0;
                break;
            case 2:
                startPosX = measuredWidth - actualDistance;
                startPosY = 0;
                endPosX = measuredWidth;
                endPosY = actualDistance;
                break;
            case 3:
                startPosX = 0;
                startPosY = measuredHeight - actualDistance;
                endPosX = actualDistance;
                endPosY = measuredHeight;
                break;
            case 4:
                startPosX = measuredWidth - actualDistance;
                startPosY = measuredHeight;
                endPosX = measuredWidth;
                endPosY = measuredHeight - actualDistance;
                break;
        }
    }

    private int dip2Px(float dip) {
        return (int) (dip * context.getResources().getDisplayMetrics().density + 0.5f);
    }

    private int px2Dip(float px) {
        return (int) (px / context.getResources().getDisplayMetrics().density + 0.5f);
    }

    public void setLabelHeight(View view, int height) {
        if (this.height != dip2Px(height)) {
            this.height = dip2Px(height);
            view.invalidate();
        }
    }

    public int getLabelHeight() {
        return px2Dip(this.height);
    }

    public void setLabelDistance(View view, int distance) {
        if (this.distance != dip2Px(distance)) {
            this.distance = dip2Px(distance);
            view.invalidate();
        }
    }

    public int getLabelDistance() {
        return px2Dip(this.distance);
    }

    public boolean isLabelVisual() {
        return visual;
    }

    public void setLabelVisual(View view, boolean visual) {
        if (this.visual != visual) {
            this.visual = visual;
            view.invalidate();
        }
    }

    public int getLabelOrientation() {
        return orientation;
    }

    public void setLabelOrientation(View view, int orientation) {
        if (this.orientation != orientation && orientation <= 4 && orientation >= 1) {
            this.orientation = orientation;
            view.invalidate();
        }
    }

    public int getLabelTextColor() {
        return textColor;
    }

    public void setLabelTextColor(View view, int textColor) {
        if (this.textColor != textColor) {
            this.textColor = textColor;
            view.invalidate();
        }
    }

    public int getLabelBackgroundColor() {
        return backgroundColor;
    }

    public void setLabelBackgroundColor(View view, int backgroundColor) {
        if (this.backgroundColor != backgroundColor) {
            this.backgroundColor = backgroundColor;
            view.invalidate();
        }
    }


    public void setLabelBackgroundAlpha(View view, int alpha) {
        if (this.alpha != alpha) {
            this.alpha = alpha;
            view.invalidate();
        }
    }

    public String getLabelText() {
        return text;
    }

    public void setLabelText(View view, String text) {
        if (this.text == null || !this.text.equals(text)) {
            this.text = text;
            view.invalidate();
        }
    }

    public int getLabelTextSize() {
        return px2Dip(this.textSize);
    }

    public void setLabelTextSize(View view, int textSize) {
        if (this.textSize != textSize) {
            this.textSize = textSize;
            view.invalidate();
        }
    }
}




Button

package com.textstay;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.Button;

public class LabelButtonView extends Button {

    LabelViewHelper utils;

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

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

    public LabelButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        utils = new LabelViewHelper(context, attrs, defStyleAttr);
    }

    @SuppressLint("WrongCall") @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        utils.onDraw(canvas, getMeasuredWidth(), getMeasuredHeight());
    }

    public void setLabelHeight(int height) {
        utils.setLabelHeight(this, height);
    }

    public int getLabelHeight() {
        return utils.getLabelHeight();
    }

    public void setLabelDistance(int distance) {
        utils.setLabelDistance(this, distance);
    }

    public int getLabelDistance() {
        return utils.getLabelDistance();
    }

    public boolean isLabelVisual() {
        return utils.isLabelVisual();
    }

    public void setLabelVisual(boolean enable) {
        utils.setLabelVisual(this, enable);
    }

    public int getLabelOrientation() {
        return utils.getLabelOrientation();
    }

    public void setLabelOrientation(int orientation) {
        utils.setLabelOrientation(this, orientation);
    }

    public int getLabelTextColor() {
        return utils.getLabelTextColor();
    }

    public void setLabelTextColor(int textColor) {
        utils.setLabelTextColor(this, textColor);
    }

    public int getLabelBackgroundColor() {
        return utils.getLabelBackgroundColor();
    }

    public void setLabelBackgroundColor(int backgroundColor) {
        utils.setLabelBackgroundColor(this, backgroundColor);
    }

    public String getLabelText() {
        return utils.getLabelText();
    }

    public void setLabelText(String text) {
        utils.setLabelText(this, text);
    }

    public int getLabelTextSize() {
        return utils.getLabelTextSize();
} public void setLabelTextSize(int textSize) { utils.setLabelTextSize(this, textSize); }}


使用方法

<com.textstay.LabelButtonView
        android:id="@+id/labelbutton"
        android:layout_width="200dp"
        android:layout_height="48dp"
        android:background="#03a9f4"
        android:gravity="center"
        android:text="Button"
        android:textColor="#ffffff"
        app:label_backgroundColor="#C2185B"
        app:label_distance="20dp"
        app:label_height="20dp"
        app:label_orientation="LEFT_TOP"
        app:label_text="HD"
        app:label_textSize="12sp" />


Imageview


package com.textstay;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.ImageView;

public class LabelImageView extends ImageView {

    LabelViewHelper utils;

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

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

    public LabelImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        utils = new LabelViewHelper(context, attrs, defStyleAttr);
    }

    @SuppressLint("WrongCall") @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        utils.onDraw(canvas, getMeasuredWidth(), getMeasuredHeight());
    }

    public void setLabelHeight(int height) {
        utils.setLabelHeight(this, height);
    }

    public int getLabelHeight() {
        return utils.getLabelHeight();
    }

    public void setLabelDistance(int distance) {
        utils.setLabelDistance(this, distance);
    }

    public int getLabelDistance() {
        return utils.getLabelDistance();
    }

    public boolean isLabelVisual() {
        return utils.isLabelVisual();
    }

    public void setLabelVisual(boolean enable) {
        utils.setLabelVisual(this, enable);
    }

    public int getLabelOrientation() {
        return utils.getLabelOrientation();
    }

    public void setLabelOrientation(int orientation) {
        utils.setLabelOrientation(this, orientation);
    }

    public int getLabelTextColor() {
        return utils.getLabelTextColor();
    }

    public void setLabelTextColor(int textColor) {
        utils.setLabelTextColor(this, textColor);
    }

    public int getLabelBackgroundColor() {
        return utils.getLabelBackgroundColor();
    }

    public void setLabelBackgroundColor(int backgroundColor) {
        utils.setLabelBackgroundColor(this, backgroundColor);
    }

    public void setLabelBackgroundAlpha(int alpha) {
        utils.setLabelBackgroundAlpha(this, alpha);
    }

    public String getLabelText() {
        return utils.getLabelText();
    }

    public void setLabelText(String text) {
        utils.setLabelText(this, text);
    }

    public int getLabelTextSize() {
        return utils.getLabelTextSize();
    }

    public void setLabelTextSize(int textSize) {
        utils.setLabelTextSize(this, textSize);
    }
}


使用方法

 <com.textstay.LabelImageView
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:src="@drawable/ic_launcher"
        app:label_backgroundColor="#C2185B"
        app:label_distance="20dp"
        app:label_height="20dp"
        app:label_orientation="LEFT_TOP"
        app:label_text="HD"
        app:label_textSize="12sp" 
        />


TextView 

package com.textstay;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.TextView;

public class LabelTextView extends TextView {

    LabelViewHelper utils;

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

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

    public LabelTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        utils = new LabelViewHelper(context, attrs, defStyleAttr);
    }

    @SuppressLint("WrongCall") @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        utils.onDraw(canvas, getMeasuredWidth(), getMeasuredHeight());
    }

    public void setLabelHeight(int height) {
        utils.setLabelHeight(this, height);
    }

    public int getLabelHeight() {
        return utils.getLabelHeight();
    }

    public void setLabelDistance(int distance) {
        utils.setLabelDistance(this, distance);
    }

    public int getLabelDistance() {
        return utils.getLabelDistance();
    }

    public boolean isLabelEnable() {
        return utils.isLabelVisual();
    }

    public void setLabelEnable(boolean enable) {
        utils.setLabelVisual(this, enable);
    }

    public int getLabelOrientation() {
        return utils.getLabelOrientation();
    }

    public void setLabelOrientation(int orientation) {
        utils.setLabelOrientation(this, orientation);
    }

    public int getLabelTextColor() {
        return utils.getLabelTextColor();
    }

    public void setLabelTextColor(int textColor) {
        utils.setLabelTextColor(this, textColor);
    }

    public int getLabelBackgroundColor() {
        return utils.getLabelBackgroundColor();
    }

    public void setLabelBackgroundColor(int backgroundColor) {
        utils.setLabelBackgroundColor(this, backgroundColor);
    }

    public String getLabelText() {
        return utils.getLabelText();
    }

    public void setLabelText(String text) {
        utils.setLabelText(this, text);
    }

    public int getLabelTextSize() {
        return utils.getLabelTextSize();
    }

    public void setLabelTextSize(int textSize) {
        utils.setLabelTextSize(this, textSize);
    }
}


使用方法

<com.textstay.LabelTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="标签textview"
        android:textSize="20sp"
        app:label_backgroundColor="#C2185B"
        app:label_distance="20dp"
        app:label_height="10dp"
        app:label_orientation="LEFT_TOP"
        app:label_text="HOT"
        app:label_textSize="12sp" 
        android:layout_marginBottom="10dp"
        />

View


package com.textstay;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.concurrent.atomic.AtomicInteger;

public class LabelView extends TextView {

    private float _offsetx;
    private float _offsety;
    private float _anchorx;
    private float _anchory;
    private float _angel;
    private int _labelViewContainerID;
    private Animation _animation = new Animation() {
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            Matrix tran = t.getMatrix();
            tran.postTranslate(_offsetx, _offsety);
            tran.postRotate(_angel, _anchorx, _anchory);
        }
    };

    public enum Gravity {
        LEFT_TOP, RIGHT_TOP
    }

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

    public LabelView(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.textViewStyle);
    }

    public LabelView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        init();

        _animation.setFillBefore(true);
        _animation.setFillAfter(true);
        _animation.setFillEnabled(true);

    }


    private void init() {

        if (!(getLayoutParams() instanceof ViewGroup.LayoutParams)) {
            LayoutParams layoutParams =
                    new LayoutParams(
                            ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.WRAP_CONTENT);
            setLayoutParams(layoutParams);
        }

        // the default value
        //setPadding(dip2Px(40), dip2Px(2), dip2Px(40), dip2Px(2));
        _labelViewContainerID = -1;

        setGravity(android.view.Gravity.CENTER);
        setTextColor(Color.WHITE);
        setTypeface(Typeface.DEFAULT_BOLD);
        setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
        setBackgroundColor(Color.BLUE);
    }

    public void setTargetView(View target, int distance, Gravity gravity) {

        if (!replaceLayout(target)) {
            return;
        }

        final int d = dip2Px(distance);
        final Gravity g = gravity;
        final View v = target;

        ViewTreeObserver vto = getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                getViewTreeObserver().removeGlobalOnLayoutListener(this);
                calcOffset(getMeasuredWidth(), d, g, v.getMeasuredWidth(), false);
            }
        });

    }


    public void setTargetViewInBaseAdapter(View target, int targetWidth, int distance, Gravity gravity) {
        if (!replaceLayout(target)) {
            return;
        }
        //measure(0, 0);
        //calcOffset(getMeasuredWidth(), distance, gravity, targetWidth, true);
        calcOffset(dip2Px(targetWidth), distance, gravity, targetWidth, true);
    }

    public void remove() {
        if (getParent() == null || _labelViewContainerID == -1) {
            return;
        }

        ViewGroup frameContainer = (ViewGroup) getParent();
        assert (frameContainer.getChildCount() == 2);
        View target = frameContainer.getChildAt(0);

        ViewGroup parentContainer = (ViewGroup) frameContainer.getParent();
        int groupIndex = parentContainer.indexOfChild(frameContainer);
        if (frameContainer.getParent() instanceof RelativeLayout) {
            for (int i = 0; i < parentContainer.getChildCount(); i++) {
                if (i == groupIndex) {
                    continue;
                }
                View view = parentContainer.getChildAt(i);
                RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) view.getLayoutParams();
                for (int j = 0; j < para.getRules().length; j++) {
                    if (para.getRules()[j] == _labelViewContainerID) {
                        para.getRules()[j] = target.getId();
                    }
                }
                view.setLayoutParams(para);
            }
        }

        ViewGroup.LayoutParams frameLayoutParam = frameContainer.getLayoutParams();
        target.setLayoutParams(frameLayoutParam);
        parentContainer.removeViewAt(groupIndex);
        frameContainer.removeView(target);
        frameContainer.removeView(this);
        parentContainer.addView(target,groupIndex);
        _labelViewContainerID = -1;
    }

    @SuppressLint("NewApi") private boolean replaceLayout(View target) {
        if (getParent() != null || target == null || target.getParent() == null || _labelViewContainerID != -1) {
            return false;
        }

        ViewGroup parentContainer = (ViewGroup) target.getParent();

        if (target.getParent() instanceof FrameLayout) {
            ((FrameLayout) target.getParent()).addView(this);
        } else if (target.getParent() instanceof ViewGroup) {

            int groupIndex = parentContainer.indexOfChild(target);
            _labelViewContainerID = generateViewId();

            // relativeLayout need copy rule
            if (target.getParent() instanceof RelativeLayout) {
                for (int i = 0; i < parentContainer.getChildCount(); i++) {
                    if (i == groupIndex) {
                        continue;
                    }
                    View view = parentContainer.getChildAt(i);
                    RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) view.getLayoutParams();
                    for (int j = 0; j < para.getRules().length; j++) {
                        if (para.getRules()[j] == target.getId()) {
                            para.getRules()[j] = _labelViewContainerID;
                        }
                    }
                    view.setLayoutParams(para);
                }
            }
            parentContainer.removeView(target);

            // new dummy layout
            FrameLayout labelViewContainer = new FrameLayout(getContext());
            ViewGroup.LayoutParams targetLayoutParam = target.getLayoutParams();
            labelViewContainer.setLayoutParams(targetLayoutParam);
            target.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

            // add target and label in dummy layout
            labelViewContainer.addView(target);
            labelViewContainer.addView(this);
            labelViewContainer.setId(_labelViewContainerID);

            // add dummy layout in parent container
            parentContainer.addView(labelViewContainer, groupIndex, targetLayoutParam);
        }
        return true;
    }

    private void calcOffset(int labelWidth, int distance, Gravity gravity, int targetWidth, boolean isDP) {

        int d = dip2Px(distance);
        int tw = isDP ? dip2Px(targetWidth) : targetWidth;

        float edge = (float) ((labelWidth - 2 * d) / (2 * 1.414));
        if (gravity == Gravity.LEFT_TOP) {
            _anchorx = -edge;
            _offsetx = _anchorx;
            _angel = -45;
        } else if (gravity == Gravity.RIGHT_TOP) {
            _offsetx = tw + edge - labelWidth;
            _anchorx = tw + edge;
            _angel = 45;
        }

        _anchory = (float) (1.414 * d + edge);
        _offsety = _anchory;

        clearAnimation();
        startAnimation(_animation);
    }

    private int dip2Px(float dip) {
        return (int) (dip * getContext().getResources().getDisplayMetrics().density + 0.5f);
    }

    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);

    public static int generateViewId() {
        for (; ; ) {
            final int result = sNextGeneratedId.get();
            // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
            int newValue = result + 1;
            if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
            if (sNextGeneratedId.compareAndSet(result, newValue)) {
                return result;
            }
        }
    }
}

使用方法  同上






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值