自定义VIEW实现应用内消息提醒上下轮播

开题贴上这张图,相信我不解释今天分享的内容,大家也已经知道了,接下来我就结合代码为大家讲解一下,这个消息自动轮播VIEW的具体实现方式。

自定义VIEW实现应用内消息提醒上下轮播_第1张图片

需求分析:

1.在ITEM上随着一条消息滑出之后,下一条消息自动滑入。

2.消息轮播可循环

3.ITEM上绑定点击事件,点击对应的ITEM,TOAST相对应的消息内容。

实现分析:

自定义VIEW继承自FrameLayout,利用Animation动画赋予前后两条被轮播的消息ITEM一个执行滑进、另一条执行滑出,然后,利用FrameLayout的bringChildToFront(待播放的VIEW),循环让被轮播的ITEM位于所有子VIEW之前。

1.准备消息ITEM

   Item分析:左边为特定的IMG标签,中间是消息提示的具体内容,右边提示更多箭头。 根据分析,Item上,左边Img标签,中间      文字内容是可变的,右边箭头不变,抽取Item实体类如下:

  MessageEntity:


/**
 * desc :消息实体
 * author:xiedong
 * data:2018/7/20
 */
public class MessageEntity {
    private String message;
    private int imgRes;


    public MessageEntity(int imgRes, String message) {
        this.message = message;
        this.imgRes = imgRes;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public int getImgRes() {
        return imgRes;
    }

    public void setImgRes(int imgRes) {
        this.imgRes = imgRes;
    }
}

2.Item实现:

由于整个Item内容比较单一,我采用TextView实现,左右图标用setCompoundDrawables()实现

 tipView.setCompoundDrawables(loadDrawable(tip.getImgRes()), null, loadDrawable(R.drawable.ic_more), null);

3.准备Item

Item的滑进、滑出动画,当前可被用户看见的消息执行由下往上滑动动画,待滑入的消息执行由下往上滑进动画,滑进后被用户可见后,执行滑出动画,下一条继续执行滑入动画,变成可见消息继续滑出,待下一条滑入........

3.1更新当前的消息并执行动画

    private void updateTipAndPlayAnimation() {
        if (curTipIndex % 2 == 0) {
            updateTip(tv_tip_out);
            tv_tip_in.startAnimation(anim_out);
            tv_tip_out.startAnimation(anim_in);
            this.bringChildToFront(tv_tip_in);
        } else {
            updateTip(tv_tip_in);
            tv_tip_out.startAnimation(anim_out);
            tv_tip_in.startAnimation(anim_in);
            this.bringChildToFront(tv_tip_out);
        }
    }

    private void updateTip(TextView tipView) {
        final MessageEntity tip = getNextTip();
        tipView.setCompoundDrawables(loadDrawable(tip.getImgRes()), null, loadDrawable(R.drawable.ic_more), null);
        if (!TextUtils.isEmpty(tip.getMessage())) {
            tipView.setText(tip.getMessage());
            tipView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    onItemClickListener.onClick(tip.getMessage());
                }
            });
        }
    }

3.2从集合中取得下一条被轮播的消息

    private MessageEntity getNextTip() {
        if (isListEmpty(tipList)) return null;
        return tipList.get(curTipIndex++ % tipList.size());
    }

3.3动画的具体创建过程

    private Animation newAnimation(float fromYValue, float toYValue) {
        Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
                Animation.RELATIVE_TO_SELF, fromYValue, Animation.RELATIVE_TO_SELF, toYValue);
        anim.setDuration(ANIM_DURATION);
        anim.setStartOffset(ANIM_DELAYED_MILLIONS);
        anim.setInterpolator(new DecelerateInterpolator());
        return anim;
    }

消息轮播VIEW的核心实现思想如上,主要是结合Animation动画配合FrameLayout的特性实现View的滑进滑出效果,上述分析我贴的是部分核心实现代码,下面我把完整的代码贴上,大家可根据具体业务场景自行扩展。

轮播View代码:


/**
 * desc :自定义view实现上下轮播的view(客户端消息轮播效果)
 * author:xiedong
 * data:2018/7/20
 */
public class LooperMessageView extends FrameLayout {
    private List tipList;
    private int curTipIndex = 0;
    private long lastTimeMillis;
    private static final int ANIM_DELAYED_MILLIONS = 3 * 1000;
    /**
     * 动画持续时长
     */
    private static final int ANIM_DURATION = 1 * 1000;
    private static final String DEFAULT_TEXT_COLOR = "#2F4F4F";
    private static final int DEFAULT_TEXT_SIZE = 16;
    private TextView tv_tip_out, tv_tip_in;
    private Animation anim_out, anim_in;
    private OnItemClickListener onItemClickListener;

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

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

    public LooperMessageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initTipFrame();
        initAnimation();
    }

    private void initTipFrame() {
        tv_tip_out = newTextView();
        tv_tip_in = newTextView();
        addView(tv_tip_in);
        addView(tv_tip_out);
    }

    private TextView newTextView() {
        TextView textView = new TextView(getContext());
        LayoutParams lp = new LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER_VERTICAL);
        textView.setLayoutParams(lp);
        textView.setCompoundDrawablePadding(10);
        textView.setGravity(Gravity.CENTER_VERTICAL);
        textView.setLines(2);
        textView.setEllipsize(TextUtils.TruncateAt.END);
        textView.setTextColor(Color.parseColor(DEFAULT_TEXT_COLOR));
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, DEFAULT_TEXT_SIZE);
        return textView;
    }

    /**
     * 将资源图片转换为Drawable对象
     *
     * @param ResId
     * @return
     */
    private Drawable loadDrawable(int ResId) {
        Drawable drawable = getResources().getDrawable(ResId);
        drawable.setBounds(0, 0, drawable.getMinimumWidth() / 4, drawable.getMinimumHeight() / 4);
        return drawable;
    }

    private void initAnimation() {
        anim_out = newAnimation(0, -1);
        anim_in = newAnimation(1, 0);
        anim_in.setAnimationListener(new Animation.AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                updateTipAndPlayAnimationWithCheck();
            }
        });
    }

    private Animation newAnimation(float fromYValue, float toYValue) {
        Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
                Animation.RELATIVE_TO_SELF, fromYValue, Animation.RELATIVE_TO_SELF, toYValue);
        anim.setDuration(ANIM_DURATION);
        anim.setStartOffset(ANIM_DELAYED_MILLIONS);
        anim.setInterpolator(new DecelerateInterpolator());
        return anim;
    }

    private void updateTipAndPlayAnimationWithCheck() {
        if (System.currentTimeMillis() - lastTimeMillis < 1000) {
            return;
        }
        lastTimeMillis = System.currentTimeMillis();
        updateTipAndPlayAnimation();
    }

    private void updateTipAndPlayAnimation() {
        if (curTipIndex % 2 == 0) {
            updateTip(tv_tip_out);
            tv_tip_in.startAnimation(anim_out);
            tv_tip_out.startAnimation(anim_in);
            this.bringChildToFront(tv_tip_in);
        } else {
            updateTip(tv_tip_in);
            tv_tip_out.startAnimation(anim_out);
            tv_tip_in.startAnimation(anim_in);
            this.bringChildToFront(tv_tip_out);
        }
    }

    private void updateTip(TextView tipView) {
        final MessageEntity tip = getNextTip();
        tipView.setCompoundDrawables(loadDrawable(tip.getImgRes()), null, loadDrawable(R.drawable.ic_more), null);
        if (!TextUtils.isEmpty(tip.getMessage())) {
            tipView.setText(tip.getMessage());
            tipView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    onItemClickListener.onClick(tip.getMessage());
                }
            });
        }
    }

    /**
     * 获取下一条消息
     *
     * @return
     */
    private MessageEntity getNextTip() {
        if (isListEmpty(tipList)) return null;
        return tipList.get(curTipIndex++ % tipList.size());
    }

    public static boolean isListEmpty(List list) {
        return list == null || list.isEmpty();
    }

    public void setTipList(List tipList) {
        this.tipList = tipList;
        curTipIndex = 0;
        updateTip(tv_tip_out);
        updateTipAndPlayAnimation();
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    interface OnItemClickListener {
        void onClick(String message);
    }
}

在布局中引入:




    

在Activity中,绑定被轮播的消息集合:


public class MainActivity extends AppCompatActivity {

    private LooperMessageView messageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        messageView = (LooperMessageView) findViewById(R.id.lmv_news);
        messageView.setTipList(generateTips());
        messageView.setOnItemClickListener(new LooperMessageView.OnItemClickListener() {
            @Override
            public void onClick(String message) {
                Toast.makeText(MainActivity.this, "正要跳转到  " + message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private List generateTips() {
        List tips = new ArrayList<>();
        tips.add(new MessageEntity(R.drawable.ic_friends, "有小伙伴艾特你了"));
        tips.add(new MessageEntity(R.drawable.ic_friend_b, "社区里有人给你发私信了"));
        return tips;
    }
}

项目源码已上传github,欢迎拍砖。自定义view实现上下轮播的view(客户端消息提醒)

你可能感兴趣的:(View)