当前位置:网站首页>Customize VIEW to realize in-app message reminder to rotate up and down
Customize VIEW to realize in-app message reminder to rotate up and down
2022-08-09 13:15:00 【Xie Dong _】
Post this picture to the title,Trust me not to explain what was shared today,Everyone already knows that,Next, I will explain it to you with the code,This message rotates automaticallyVIEW的具体实现方式.
需求分析:
1.在ITEMAfter sliding out with a message,The next message slides in automatically.
2.The message carousel can be looped
3.ITEM上绑定点击事件,点击对应的ITEM,TOASTcorresponding message content.
实现分析:
自定义VIEW继承自FrameLayout,利用AnimationThe animation gives two messages that are rotated before and afterITEMOne performs slide-in、The other executes the slide out,然后,利用FrameLayout的bringChildToFront(待播放的VIEW),Loop lets be rotatedITEMlocated in all subVIEW之前.
1.准备消息ITEM
Item分析:Left is specificIMG标签,In the middle is the specific content of the message prompt,More arrows are indicated on the right. 根据分析,Item上,左边Img标签,中间 Text content is variable,The right arrow remains unchanged,抽取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实现,Left and right icons are usedsetCompoundDrawables()实现
tipView.setCompoundDrawables(loadDrawable(tip.getImgRes()), null, loadDrawable(R.drawable.ic_more), null);
3.准备Item
Itemslide in、滑出动画,The message currently visible to the user performs a bottom-up slide animation,The message to be slid in performs the animation of sliding in from bottom to top,After being swiped in and visible to the user,Perform a slide out animation,The next one continues the slide-in animation,Become visible message and continue to slide out,Wait for the next one to slide in........
3.1Update the current message and perform the animation
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.2Get the next message to be rotated from the collection
private MessageEntity getNextTip() {
if (isListEmpty(tipList)) return null;
return tipList.get(curTipIndex++ % tipList.size());
}
3.3The specific creation process of animation
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;
}
消息轮播VIEWThe core realization idea is as above,主要是结合Animation动画配合FrameLayout的特性实现ViewThe slide in slide out effect,The above analysis I posted is part of the core implementation code,I paste the complete code below,You can expand by yourself according to specific business scenarios.
轮播View代码:
/**
* desc :自定义viewRealize up and down rotationview(Client message carousel effect)
* 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;
}
/**
* Convert the resource image to 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中,Binds a collection of messages to be rotated:
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, "About to jump to " + message, Toast.LENGTH_SHORT).show();
}
});
}
private List<MessageEntity> generateTips() {
List<MessageEntity> tips = new ArrayList<>();
tips.add(new MessageEntity(R.drawable.ic_friends, "There is a little friend Aite you"));
tips.add(new MessageEntity(R.drawable.ic_friend_b, "Someone in the community has sent you a private message"));
return tips;
}
}
项目源码已上传github,欢迎拍砖.自定义viewRealize up and down rotationview(Client message alerts)
边栏推荐
- Nature:猪死亡1小时后,器官再次运转
- 读写分离后,性能居然提升100%了呀
- 鹅厂机器狗花式穿越10m梅花桩:前空翻、单桩跳、起身作揖...全程不打一个趔趄...
- 虚拟机安装出现的问题汇总
- 26、管道参数替换命令xargs
- Manchester city launch emotional intelligence scarf can be detected, give the fans
- 问题来了:4GB物理内存的机器上申请8G内存能成功吗?
- ABAP 面试题:如何使用 ABAP 编程语言的 System CALL 接口,直接执行 ABAP 服务器所在操作系统的 shell 命令?
- 微服务架构的核心关键点
- Flutter入门进阶之旅(八)Button Widget
猜你喜欢
问题来了:4GB物理内存的机器上申请8G内存能成功吗?
Scala Advanced (7): Collection Content Summary (Part 1)
ThreadLocal的简单理解
C# Get system installed .NET version
微信一面:一致性哈希是什么,使用场景,解决了什么问题?
h264 protocol
【微服务~远程调用】整合RestTemplate、WebClient、Feign
Information system project managers must memorize the core test sites (63) The main process of project portfolio management & DIPP analysis
自定义VIEW实现应用内消息提醒上下轮播
AQS Synchronization Component - FutureTask Analysis and Use Cases
随机推荐
一甲子,正青春,CCF创建六十周年庆典在苏州举行
Blazor Server (9) from scratch -- modify Layout
MongoDB-查询中$all的用法介绍
关于Retrofit网络请求URL中含有可变参数的处理
字符串转换整数 (atoi)
注释、关键字、标识符的区别你知道吗?
Manchester city launch emotional intelligence scarf can be detected, give the fans
曲鸟全栈UI自动化教学(八):框架代码讲解和进一步优化
Shell正则表达式,三剑客之grep命令
Golang学习之路(五):Golang的函数
京东架构师呕心整理:jvm与性能调优有哪些核心技术知识点
箭头函数和普通函数的常见区别
Report: The number of students who want to learn AI has increased by 200%, and there are not enough teachers
数据挖掘-06
基于STM32+铂电阻设计的测温仪
非科班AI小哥火了:他没有ML学位,却拿到DeepMind的offer
Adalvo acquires its first branded product, Onsolis
go基础之web获取参数
Go-based web access parameters
The redis library cannot be imported