当前位置:网站首页>自定义VIEW实现应用内消息提醒上下轮播
自定义VIEW实现应用内消息提醒上下轮播
2022-08-09 12:04:00 【谢栋_】
开题贴上这张图,相信我不解释今天分享的内容,大家也已经知道了,接下来我就结合代码为大家讲解一下,这个消息自动轮播VIEW的具体实现方式。
需求分析:
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<MessageEntity> 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<MessageEntity> 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);
}
}
在布局中引入:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#e2e2e1"
tools:context=".MainActivity">
<com.zhuandian.loopermessageview.LooperMessageView
android:id="@+id/lmv_news"
android:layout_width="match_parent"
android:layout_height="80dp"
android:padding="10dp"
android:layout_marginTop="10px"
android:background="#fff" />
</android.support.constraint.ConstraintLayout>
在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<MessageEntity> generateTips() {
List<MessageEntity> 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(客户端消息提醒)
边栏推荐
猜你喜欢
微信一面:一致性哈希是什么,使用场景,解决了什么问题?
MongoDB-查询中$all的用法介绍
你没见过的《老友记》镜头,AI给补出来了|ECCV 2022
web course design
Intranet penetration tool ngrok usage tutorial
报告:想学AI的学生数量已涨200%,老师都不够用了
ABAP 报表中如何以二进制方式上传本地文件试读版
Scala 高阶(七):集合内容汇总(上篇)
ABAP interview questions: how to use the System CALL interface of the ABAP programming language, direct execution ABAP server operating System's shell command?
专业人士使用的 11 种渗透测试工具
随机推荐
HAproxy: load balancing
Too much volume... Tencent was asked on the side that the memory was full, what would happen?
数字化转型之支撑保障单元
Manchester city launch emotional intelligence scarf can be detected, give the fans
Rust从入门到精通04-数据类型
非科班AI小哥火了:他没有ML学位,却拿到DeepMind的offer
PM2 configuration file
世界第4疯狂的科学家,在103岁生日那天去世了
Double pointer - the role of char **, int **
ThreadLocal的简单理解
JD.com architects tidy up: what are the core technical knowledge points of jvm and performance tuning
Modify the VOT2018.json file and remove the color in the image path
Reading and writing after separation, performance were up 100%
Go-based web access parameters
阿里高工带来的20022最新面试总结太香了
阿里云新增三大高性能计算解决方案,助力生命科学行业快速发展
智驾科技完成C1轮融资,此前2轮已融4.5亿元
Web console control edit box
GRPC整体学习
Intranet penetration tool ngrok usage tutorial