Android给控件添加消息提醒

Android给控件添加消息提醒

一、需求

IM有未读消息提醒或者购物车会有购物数量

二、一般有两种做法

1、传统做法

用一个framelayout布局或者是相对布局,然后使得两个空间重叠,达到右上角提醒的功能

2、自定义控件(今天重点)

自定义控件,要集成textview或者其它控件,然后在实现我们需要的功能就OK了。

三、自定义的实现类

package com.lingling.anwanfei.testan;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.TabWidget;
import android.widget.TextView;

/**
* 作者:
* 时间: 2017/7/9
* 邮箱:
* QQ:546513287
*/

public class BadgeView extends TextView {
/* 位于控件左上角 */
public static final int POSITION_TOP_LEFT = 1;
/* 位于控件右上角 */
public static final int POSITION_TOP_RIGHT = 2;
/* 位于控件右下角 */
public static final int POSITION_BOTTOM_LEFT = 3;
/* 位于控件左下角 */
public static final int POSITION_BOTTOM_RIGHT = 4;
/* 位于控件正中央 */
public static final int POSITION_CENTER = 5;

/* 默认margin */
private static final int DEFAULT_MARGIN_DIP = 5;
/* 默认左右padding */
private static final int DEFAULT_LR_PADDING_DIP = 5;
/* 默认添加控件的圆角 */
private static final int DEFAULT_CORNER_RADIUS_DIP = 8;
/* 默认位置:右上角 */
private static final int DEFAULT_POSITION = POSITION_TOP_RIGHT;
/* 默认标签的背景色为红色 */
private static final int DEFAULT_BADGE_COLOR = Color.parseColor("#CCFF0000");
/* 默认标签颜色为白色 */
private static final int DEFAULT_TEXT_COLOR = Color.WHITE;

/* 动画 */
private static Animation fadeIn;
private static Animation fadeOut;

private Context context;
private View target;

private int badgePosition;
private int badgeMarginH;
private int badgeMarginV;
private int badgeColor;

private boolean isShown;

private ShapeDrawable badgeBg;

private int targetTabIndex;

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

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

/**
 * Constructor -
 * <p>
 * create a new BadgeView instance attached to a target {@link View}.
 *
 * @param context context for this view.
 * @param target  the View to attach the badge to.
 */
public BadgeView(Context context, View target) {
    this(context, null, android.R.attr.textViewStyle, target, 0);
}

/**
 * Constructor -
 * <p>
 * create a new BadgeView instance attached to a target {@link TabWidget}
 * tab at a given index.
 *
 * @param context context for this view.
 * @param target  the TabWidget to attach the badge to.
 * @param index   the position of the tab within the target.
 */
public BadgeView(Context context, TabWidget target, int index) {
    this(context, null, android.R.attr.textViewStyle, target, index);
}

public BadgeView(Context context, AttributeSet attrs, int defStyle) {
    this(context, attrs, defStyle, null, 0);
}

public BadgeView(Context context, AttributeSet attrs, int defStyle, View target, int tabIndex) {
    super(context, attrs, defStyle);
    init(context, target, tabIndex);
}

private void init(Context context, View target, int tabIndex) {

    this.context = context;
    this.target = target;
    this.targetTabIndex = tabIndex;

    // apply defaults
    badgePosition = DEFAULT_POSITION;
    badgeMarginH = dipToPixels(DEFAULT_MARGIN_DIP);
    badgeMarginV = badgeMarginH;
    badgeColor = DEFAULT_BADGE_COLOR;

    setTypeface(Typeface.DEFAULT_BOLD);
    int paddingPixels = dipToPixels(DEFAULT_LR_PADDING_DIP);
    setPadding(paddingPixels, 0, paddingPixels, 0);
    setTextColor(DEFAULT_TEXT_COLOR);

    fadeIn = new AlphaAnimation(0, 1);
    fadeIn.setInterpolator(new DecelerateInterpolator());
    fadeIn.setDuration(200);

    fadeOut = new AlphaAnimation(1, 0);
    fadeOut.setInterpolator(new AccelerateInterpolator());
    fadeOut.setDuration(200);

    isShown = false;

    if (this.target != null) {
        applyTo(this.target);
    } else {
        show();
    }

}

private void applyTo(View target) {

    ViewGroup.LayoutParams lp = target.getLayoutParams();
    ViewParent parent = target.getParent();
    FrameLayout container = new FrameLayout(context);

    if (target instanceof TabWidget) {

        // set target to the relevant tab child container
        target = ((TabWidget) target).getChildTabViewAt(targetTabIndex);
        this.target = target;

        ((ViewGroup) target).addView(container,
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));

        this.setVisibility(View.GONE);
        container.addView(this);

    } else {

        // TODO verify that parent is indeed a ViewGroup
        ViewGroup group = (ViewGroup) parent;
        int index = group.indexOfChild(target);

        group.removeView(target);
        group.addView(container, index, lp);

        container.addView(target);

        this.setVisibility(View.GONE);
        container.addView(this);

        group.invalidate();

    }

}

/**
 * Make the badge visible in the UI.
 */
public void show() {
    show(false, null);
}

/**
 * Make the badge visible in the UI.
 *
 * @param animate flag to apply the default fade-in animation.
 */
public void show(boolean animate) {
    show(animate, fadeIn);
}

/**
 * Make the badge visible in the UI.
 *
 * @param anim Animation to apply to the view when made visible.
 */
public void show(Animation anim) {
    show(true, anim);
}

/**
 * Make the badge non-visible in the UI.
 */
public void hide() {
    hide(false, null);
}

/**
 * Make the badge non-visible in the UI.
 *
 * @param animate flag to apply the default fade-out animation.
 */
public void hide(boolean animate) {
    hide(animate, fadeOut);
}

/**
 * Make the badge non-visible in the UI.
 *
 * @param anim Animation to apply to the view when made non-visible.
 */
public void hide(Animation anim) {
    hide(true, anim);
}

/**
 * Toggle the badge visibility in the UI.
 */
public void toggle() {
    toggle(false, null, null);
}

/**
 * Toggle the badge visibility in the UI.
 *
 * @param animate flag to apply the default fade-in/out animation.
 */
public void toggle(boolean animate) {
    toggle(animate, fadeIn, fadeOut);
}

/**
 * Toggle the badge visibility in the UI.
 *
 * @param animIn  Animation to apply to the view when made visible.
 * @param animOut Animation to apply to the view when made non-visible.
 */
public void toggle(Animation animIn, Animation animOut) {
    toggle(true, animIn, animOut);
}

private void show(boolean animate, Animation anim) {
    if (getBackground() == null) {
        if (badgeBg == null) {
            badgeBg = getDefaultBackground();
        }
        setBackgroundDrawable(badgeBg);
    }
    applyLayoutParams();

    if (animate) {
        this.startAnimation(anim);
    }
    this.setVisibility(View.VISIBLE);
    isShown = true;
}

private void hide(boolean animate, Animation anim) {
    this.setVisibility(View.GONE);
    if (animate) {
        this.startAnimation(anim);
    }
    isShown = false;
}

private void toggle(boolean animate, Animation animIn, Animation animOut) {
    if (isShown) {
        hide(animate && (animOut != null), animOut);
    } else {
        show(animate && (animIn != null), animIn);
    }
}

/**
 * Increment the numeric badge label. If the current badge label cannot be converted to
 * an integer value, its label will be set to "0".
 *
 * @param offset the increment offset.
 */
public int increment(int offset) {
    CharSequence txt = getText();
    int i;
    if (txt != null) {
        try {
            i = Integer.parseInt(txt.toString());
        } catch (NumberFormatException e) {
            i = 0;
        }
    } else {
        i = 0;
    }
    i = i + offset;
    setText(String.valueOf(i));
    return i;
}

/**
 * Decrement the numeric badge label. If the current badge label cannot be converted to
 * an integer value, its label will be set to "0".
 *
 * @param offset the decrement offset.
 */
public int decrement(int offset) {
    return increment(-offset);
}

private ShapeDrawable getDefaultBackground() {

    int r = dipToPixels(DEFAULT_CORNER_RADIUS_DIP);
    float[] outerR = new float[]{r, r, r, r, r, r, r, r};

    RoundRectShape rr = new RoundRectShape(outerR, null, null);
    ShapeDrawable drawable = new ShapeDrawable(rr);
    drawable.getPaint().setColor(badgeColor);

    return drawable;

}

private void applyLayoutParams() {

    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

    switch (badgePosition) {
        case POSITION_TOP_LEFT:
            lp.gravity = Gravity.LEFT | Gravity.TOP;
            lp.setMargins(badgeMarginH, badgeMarginV, 0, 0);
            break;
        case POSITION_TOP_RIGHT:
            lp.gravity = Gravity.RIGHT | Gravity.TOP;
            lp.setMargins(0, badgeMarginV, badgeMarginH, 0);
            break;
        case POSITION_BOTTOM_LEFT:
            lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
            lp.setMargins(badgeMarginH, 0, 0, badgeMarginV);
            break;
        case POSITION_BOTTOM_RIGHT:
            lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
            lp.setMargins(0, 0, badgeMarginH, badgeMarginV);
            break;
        case POSITION_CENTER:
            lp.gravity = Gravity.CENTER;
            lp.setMargins(0, 0, 0, 0);
            break;
        default:
            break;
    }

    setLayoutParams(lp);

}

/**
 * Returns the target View this badge has been attached to.
 */
public View getTarget() {
    return target;
}

/**
 * Is this badge currently visible in the UI?
 */
@Override
public boolean isShown() {
    return isShown;
}

/**
 * Returns the positioning of this badge.
 * <p>
 * one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, POSITION_BOTTOM_LEFT, POSITION_BOTTOM_RIGHT, POSTION_CENTER.
 */
public int getBadgePosition() {
    return badgePosition;
}

/**
 * Set the positioning of this badge.
 *
 * @param layoutPosition one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, POSITION_BOTTOM_LEFT, POSITION_BOTTOM_RIGHT, POSTION_CENTER.
 */
public void setBadgePosition(int layoutPosition) {
    this.badgePosition = layoutPosition;
}

/**
 * Returns the horizontal margin from the target View that is applied to this badge.
 */
public int getHorizontalBadgeMargin() {
    return badgeMarginH;
}

/**
 * Returns the vertical margin from the target View that is applied to this badge.
 */
public int getVerticalBadgeMargin() {
    return badgeMarginV;
}

/**
 * Set the horizontal/vertical margin from the target View that is applied to this badge.
 *
 * @param badgeMargin the margin in pixels.
 */
public void setBadgeMargin(int badgeMargin) {
    this.badgeMarginH = badgeMargin;
    this.badgeMarginV = badgeMargin;
}

/**
 * Set the horizontal/vertical margin from the target View that is applied to this badge.
 *
 * @param horizontal margin in pixels.
 * @param vertical   margin in pixels.
 */
public void setBadgeMargin(int horizontal, int vertical) {
    this.badgeMarginH = horizontal;
    this.badgeMarginV = vertical;
}

/**
 * Returns the color value of the badge background.
 */
public int getBadgeBackgroundColor() {
    return badgeColor;
}

/**
 * Set the color value of the badge background.
 *
 * @param badgeColor the badge background color.
 */
public void setBadgeBackgroundColor(int badgeColor) {
    this.badgeColor = badgeColor;
    badgeBg = getDefaultBackground();
}

private int dipToPixels(int dip) {
    Resources r = getResources();
    float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, r.getDisplayMetrics());
    return (int) px;
}
    }

四、使用(直接上代码)

package com.lingling.anwanfei.testan;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

private TextView textview;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    textview = (TextView) findViewById(R.id.textview);
    final BadgeView badgeView = new BadgeView(this, textview);

    //设置提示点的位置
    badgeView.setBadgePosition(BadgeView.POSITION_TOP_RIGHT);

    badgeView.setText("+9");
    //显示,不调用此方法,不会显示,同理,也可以隐藏.hide()
    badgeView.show();

    badgeView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            badgeView.hide();
            Toast.makeText(MainActivity.this, "消息被干", Toast.LENGTH_SHORT).show();
        }
    });

    //设置背景颜色
    badgeView.setBadgeBackgroundColor(Color.RED);

    //設置透明度
    badgeView.setAlpha(0.9f);

    //設置動畫
    ScaleAnimation scaleAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f,
            Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    scaleAnimation.setDuration(200);
    badgeView.setAnimation(scaleAnimation);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值