一、实现背景
项目中,闪购页面 用于自动切换 展示 购买信息,就是那种 “xxx 10s 买了huawei p30 ” 然后自动翻滚上去,接着底部向上滑出下一条。效果如下图。(感觉有点像连续多个Toast) 也可参考小红书的闪购页面~
即,从下面较快的出现,停留展示一会,在缓慢的向上滑出。
二、实现思路
一开始想的是,使用TextSwitcher实现,因为之前做过类似的文字切换。但效果给UI看后表示不行。因为要参考小红书的效果来,就去瞅了瞅。特点是 文字是一条一条的出现,而TextSwitcher是连着两个Text进行翻转。所以考虑自定义,使用属性动画来实现。
!2天后来更新:上面用属性动画实现,在红米5表现ok;但是其他手机(荣耀、oppo)都不行,只有第一次效果ok,后面就闪过或者只出现两次 就没了。 试了很多次又查了资料,说 属性动画 是做不到循环的(原因不清楚),所以改为使用view动画。
三、代码说明
1、方式一,属性动画(效果不佳,弃用了)
代码很简单,有注释。在代码中调用
//显示飘窗
mAutoSwitchTextView.setData(list);
即可展示出来。
/**
* @apiNote 自动向上翻滚的view,用于信息展示~
* @author hufy
* @date 2019/7/4 17:34
*/
public class AutoSwitchTextView extends RelativeLayout {
/**
* 展示的数据
*/
private List<FlashBuyerInfo.Buyer> dataList = new ArrayList<>();
/**
* 用于翻滚的textView
*/
private TextView mTextView;
/**
* index
*/
private int index = 0;
/**
* 动画集合
*/
private AnimatorSet mAnimatorSet;
public AutoSwitchTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
mTextView = new TextView(context);
mTextView.setTextColor(ResUtil.getColor(R.color.common_color_ffffff));
mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10);
mTextView.setBackgroundResource(R.drawable.text_switch_bg);
mTextView.setPadding(CommonUtils.dip2px(8), 0 ,CommonUtils.dip2px(8) ,0);
mTextView.setGravity(Gravity.CENTER);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
addView(mTextView, layoutParams);
}
/**
* 设置要展示的数据,会自动开始翻滚。
* @param dataList
*/
public void setData(List<FlashBuyerInfo.Buyer> dataList){
this.dataList = dataList;
setVisibility(View.VISIBLE);
start();
}
/**
* 快速向上滑动text、停留展示、向上滑出、等待x 秒后 继续下一个text 。
*/
private void start(){
int size = dataList.size();
index = 0;
setTextInfo(index);
mAnimatorSet = new AnimatorSet();
//从底部出现
ObjectAnimator showAnimator = ObjectAnimator.ofFloat(mTextView, "translationY", 100, 0);
showAnimator.setDuration(500);
//向上滑出
ObjectAnimator outAnimator = ObjectAnimator.ofFloat(mTextView, "translationY", 0, -100);
outAnimator.setDuration(1000);
outAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//动画结束后,继续下一个
index++;
if (index <= size - 1){
setTextInfo(index);
long nextPopupTime = getNextPopupTime(index);
mAnimatorSet.play(outAnimator).after(1500).after(showAnimator);
mAnimatorSet.setStartDelay(nextPopupTime);
mAnimatorSet.start();
}
}
});
mAnimatorSet.play(outAnimator).after(1500).after(showAnimator);
mAnimatorSet.start();
}
/**
* 结束动画
*/
public void finish(){
if (mAnimatorSet != null) {
mAnimatorSet.end();
}
}
/**
* 获取 等待多久后 继续下一条弹窗
* @param index
* @return
*/
private long getNextPopupTime(int index) {
FlashBuyerInfo.Buyer buyer = dataList.get(index);
return buyer.getNextPopupTime() * 1000;
}
/**
* 设置文字、图片
* @param index
*/
private void setTextInfo(int index) {
FlashBuyerInfo.Buyer buyer = dataList.get(index);
String text = buyer.getText();
mTextView.setText(text);
}
}
xml中使用 很简单:
<AutoSwitchTextView
android:id="@+id/flash_sale_auto_switch_text"
android:layout_marginTop="250dp"
android:layout_marginLeft="@dimen/aku_margin_8"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:gravity="center"/>
方式二、view动画(最后采取的方式)
就是写两个view动画,一个从底部出现到中间,结束后另一个从中间向上滑出(滑出的时机要延迟一会,用于信息的停留展示)。然后结束后修改信息内容,在次执行。
/**
* @apiNote 自动向上翻滚的view,~
* @author hufy
* @date 2019/7/4 17:34
*/
public class AutoSwitchTextView extends RelativeLayout {
/**
* 展示的数据
*/
private List<FlashBuyerInfo.Buyer> dataList = new ArrayList<>();
/**
* 用于翻滚的textView
*/
private TextView mTextView;
/**
* index
*/
private int index = 0;
public AutoSwitchTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
mTextView = new TextView(context);
mTextView.setTextColor(ResUtil.getColor(R.color.common_color_ffffff));
mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10);
mTextView.setBackgroundResource(R.drawable.text_switch_bg);
mTextView.setPadding(CommonUtils.dip2px(8), 0 ,CommonUtils.dip2px(8) ,0);
mTextView.setGravity(Gravity.CENTER);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
addView(mTextView, layoutParams);
}
/**
* 设置要展示的数据,会自动开始翻滚。
* @param dataList
*/
public void setData(List<FlashBuyerInfo.Buyer> dataList){
this.dataList = dataList;
setVisibility(View.VISIBLE);
start();
}
/**
* 快速向上滑动text、停留展示、向上滑出、等待x 秒后 继续下一个text 。
*/
private void start(){
int size = dataList.size();
index = 0;
setTextInfo(index);
//1.从底部出现
TranslateAnimation showAnimator = new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
Animation.RELATIVE_TO_PARENT, 1, Animation.ABSOLUTE, 0);
showAnimator.setDuration(500);
showAnimator.setFillAfter(true);
//2、停留1.5s 向上滑出
TranslateAnimation outAnimator = new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.RELATIVE_TO_SELF,
0, Animation.ABSOLUTE, 0, Animation.RELATIVE_TO_PARENT, -1);
outAnimator.setDuration(1000);
outAnimator.setFillAfter(true);
outAnimator.setStartOffset(1500);
showAnimator.setAnimationListener(new AnimationEndListener() {
@Override
void onAnimationFinish(Animation animation) {
mTextView.startAnimation(outAnimator);
}
});
outAnimator.setAnimationListener(new AnimationEndListener() {
@Override
void onAnimationFinish(Animation animation) {
index++;
if (index <= size - 1){
setTextInfo(index);
long nextPopupTime = getNextPopupTime(index);
showAnimator.setStartOffset(nextPopupTime);
mTextView.startAnimation(showAnimator);
}
}
});
mTextView.startAnimation(showAnimator);
}
/**
* 结束动画
*/
public void finish(){
if (mTextView != null) {
mTextView.clearAnimation();
}
}
/**
* 获取 等待多久后 继续下一条弹窗
* @param index
* @return
*/
private long getNextPopupTime(int index) {
FlashBuyerInfo.Buyer buyer = dataList.get(index);
return buyer.getNextPopupTime() * 1000;
}
/**
* 设置文字、图片
* @param index
*/
private void setTextInfo(int index) {
FlashBuyerInfo.Buyer buyer = dataList.get(index);
String text = buyer.getText();
mTextView.setText(text);
}
abstract class AnimationEndListener implements Animation.AnimationListener{
@Override
public void onAnimationStart(Animation animation) {
//nothing
}
@Override
public void onAnimationEnd(Animation animation) {
onAnimationFinish(animation);
}
@Override
public void onAnimationRepeat(Animation animation) {
//nothing
}
abstract void onAnimationFinish(Animation animation);
}
}