当前位置:网站首页>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)
边栏推荐
- 告别手摇织布机的AI时代
- 问题来了:4GB物理内存的机器上申请8G内存能成功吗?
- FFmpeg在win10上编译安装(配置libx264)
- Gumbel_Softmax 概要
- 两个链表相加
- Go 事,如何成为一个Gopher ,并在7天找到 Go 语言相关工作,第1篇
- WeChat side: what is consistent hashing, usage scenarios, and what problems does it solve?
- Flutter入门进阶之旅(十)Dialog&Toast
- WeChat payment development process
- GPT-3组合DALL·E,60秒内搞定游戏设定和原型动画!网友看后:这游戏想玩
猜你喜欢
数字化转型之支撑保障单元
C# Get system installed .NET version
Flutter入门进阶之旅(六)Layout Widget
自定义VIEW实现应用内消息提醒上下轮播
用 API Factory 产品生成 API 文档
LeetCode #101. 对称二叉树
非科班AI小哥火了:他没有ML学位,却拿到DeepMind的offer
1小时直播招募令:行业大咖干货分享,企业报名开启丨量子位·视点
Programmer's Exclusive Romance - Use 3D Engine to Realize Fireworks in 5 Minutes
苹果Meta都在冲的Pancake技术,中国VR团队YVR竟抢先交出产品答卷
随机推荐
h264协议
[Interview high-frequency questions] Linked list high-frequency questions that can be gradually optimized
Flutter入门进阶之旅(五)Image Widget
MySQL 原理与优化,Group By 优化 技巧
AQS同步组件-FutureTask解析和用例
京东架构师呕心整理:jvm与性能调优有哪些核心技术知识点
大佬们,请教一下,我看官方文档中,sqlserver cdc只支持2012版之后的,对于sqlser
Say goodbye to the AI era of hand looms
Go-based web access parameters
Flutter入门进阶之旅(七)GestureDetector
告别手摇织布机的AI时代
h264 protocol
ABAP interview questions: how to use the System CALL interface of the ABAP programming language, direct execution ABAP server operating System's shell command?
无重复字符的最长子串
Shell之常用小工具(sort、uniq、tr、cut)
"Digital Economy Panorama White Paper" Special Analysis of Banking Industry Intelligent Marketing Application Released
【HCIP持续更新】IS-IS协议原理与配置
无需精子卵子子宫体外培育胚胎,Cell论文作者这番话让网友们炸了
数据挖掘-05
金融业“限薪令”出台/ 软银出售过半阿里持仓/ DeepMind新实验室成立... 今日更多新鲜事在此...