Android TV 3D卡片无限循环效果
作者:小纸箱 发布时间:2022-03-26 04:06:48
标签:Android,TV,无限循环
TV 3D卡片无限循环效果,供大家参考,具体内容如下
##前言
1、需求:实现3个卡片实现无限循环效果:1-2-3-1-2-3-1…,而且要实现3D效果:中间突出,两侧呈角度显示
2、Viewpager实现方式
(1) LoopViewpager,有兴趣的同学可以去github上看一下。
(2) 通过定义一个item的个数Integer,MAX,然后设置初始位置为:Integer,MAX/2。
以上方式如果简单的加载图片这种方式还可取,由于需求3个界面内部控件比较多,在加上需要实现自定义的的3D效果,使用ViewPager实现难为了小编,于是舍弃只能自己码代码了,欲哭无泪!!!
##思路
自定义View + 属性动画ObjectAnimator
按键事件特殊处理。
##实现方式
1、ObjectAnimator属性动画的知识准备。
2、父不居中自定义ScheduleView,View2, View3
<com.base.module.gvclauncher2.ui.ScheduleView
android:id="@+id/schedule_view"
android:layout_width="@dimen/main_card_width"
android:layout_height="@dimen/main_card_height"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/main_card_margin_top"
android:focusable="true"
android:nextFocusLeft="@+id/contacts_view"
android:nextFocusRight="@+id/call_view">
</com.base.module.gvclauncher2.ui.ScheduleView>
其中android:layout_gravity=“center_horizontal”,使卡片在界面的正中间,其余两张的卡片也是如此,达到3个View的起始位置一直,这样方便之后的动画旋转。
2.添加自定义ScheduleView
public class ScheduleView extends BasePhoneView {
private static final String TAG = "CallFragment";
private static final boolean DEBUG = true;
private Context mContext;
private View mRootView;
private FrameLayout mMainView;
private ScheduleContract.View mView;
private ScheduleContract.Presenter mPresenter;
public ScheduleView(Context context) {
super(context);
this.mContext = context;
initView();
}
public ScheduleView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
initView();
}
public ScheduleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
initView();
}
private void initView() {
findView();
initData();
}
private void findView() {
mRootView = LayoutInflater.from(mContext).inflate(R.layout.fragment_schedule, this);
mMainView = (FrameLayout) mRootView.findViewById(R.id.schedule_contains);
mMainView.setVisibility(View.VISIBLE);
}
private void initData() {
mMainView.removeAllViews();
mView = ScheduleContractFactory.createScheduleView(mContext);
mMainView.addView((View) mView);
mPresenter = ScheduleContractFactory.createSchedulePresenter(mContext, mView);
mPresenter.onCreate();
//这里只是使用mvp的形式添加view.
}
@Override
public void clearAllFocus() {
//清除所有的焦点
if (mView != null) {
mView.clearAllFocus();
}
}
@Override
public void requestFirstFocus() {
//第一个控件强行指定焦点
if (mView != null) {
mView.requestFirstFocus();
}
}
@Override
public void updateListData() {
//更新列表显示
if (mPresenter != null) {
mPresenter.reloadConferenceList();
}
}
}
其中fragment_schedule.xml中只有一个简单的FrameLayout. View2 和View3类似。
3. 动画Util
(1) 设置3个卡片的初始位置
public final static float RUN_Y = 22.0f;
public final static float RUN_LARGE_Y = 24.0f;
public final static float RUN_Y_NEGATIVE = -22.0f;
public final static float RUN_LARGE_Y_NEGATIVE = -24.0f;
public final static float RUN_X = 1235.0f;
public final static float RUN_X_NEGATIVE = -1235.0f;
public final static float RUN_LARGE_X = 1366.0f;
public final static float RUN_LARGE_X_NEGATIVE = -1366.0f;
public void initLeftAnimator(View leftView) {
leftView.setTranslationX(RUN_X_NEGATIVE);//离屏幕中心偏移距离
leftView.setRotationY(RUN_Y);//旋转角度
leftView.setAlpha(LEFT_RIGHT_ALPHA);//设置透明度
}
public void initRightAnimator(View rightView) {
rightView.setTranslationX(RUN_X);//离屏幕中心偏移距离
rightView.setRotationY(RUN_Y_NEGATIVE);//旋转角度
rightView.setAlpha(LEFT_RIGHT_ALPHA);//设置透明度
}
public void initMidAnimator(View midView) {
//由于初始位置在xml中设定是在正中间,这里就不重新设置偏移量
midView.setAlpha(MIDDLE_ALPHA);
}
public void midToLeftAnimator(final View runView, boolean anim) {
ObjectAnimator animatorX = ObjectAnimator.ofFloat(runView, "translationX", 0, RUN_X_NEGATIVE); //中间的起始位置未0
ObjectAnimator animatorZ = ObjectAnimator.ofFloat(runView, "rotationY", 0, RUN_Y);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(runView, "alpha", MIDDLE_ALPHA, LEFT_RIGHT_ALPHA);
mMidToLeftAnimator = new AnimatorSet();
mMidToLeftAnimator.play(animatorX).with(animatorZ).with(animator3);
//anim设置是否需要动画执行时间
if (anim) {
mMidToLeftAnimator.setDuration(DURATION);
} else {
mMidToLeftAnimator.setDuration(0);
}
mMidToLeftAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
mIsScrolling = true;
}
@Override
public void onAnimationEnd(Animator animation) {
//mIsScrolling来判断动画是否完成,来控制下一次动画是否需要执行
mIsScrolling = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mMidToLeftAnimator.start();
}
public void midToRightAnimator(final View runView, boolean anim) {
ObjectAnimator animatorX = ObjectAnimator.ofFloat(runView, "translationX", 0, RUN_X);
ObjectAnimator animatorZ = ObjectAnimator.ofFloat(runView, "rotationY", 0, RUN_Y_NEGATIVE);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(runView, "alpha", MIDDLE_ALPHA, LEFT_RIGHT_ALPHA);
mMidToRightAnimator = new AnimatorSet();
mMidToRightAnimator.play(animatorX).with(animatorZ).with(animator3);
if (anim) {
mMidToRightAnimator.setDuration(DURATION);
} else {
mMidToRightAnimator.setDuration(0);
}
mMidToRightAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
mIsScrolling = true;
}
@Override
public void onAnimationEnd(Animator animation) {
mIsScrolling = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mMidToRightAnimator.start();
}
public void rightToMidAnimator(final View runView, boolean anim) {
ObjectAnimator animatorX = ObjectAnimator.ofFloat(runView, "translationX", RUN_X, 0);
ObjectAnimator animatorZ = ObjectAnimator.ofFloat(runView, "rotationY", RUN_Y_NEGATIVE, 0);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(runView, "alpha", LEFT_RIGHT_ALPHA, MIDDLE_ALPHA);
mRightToMidAnimator = new AnimatorSet();
mRightToMidAnimator.play(animatorX).with(animatorZ).with(animator3);
if (anim) {
mRightToMidAnimator.setDuration(DURATION);
} else {
mRightToMidAnimator.setDuration(0);
}
mRightToMidAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
mIsScrolling = true;
}
@Override
public void onAnimationEnd(Animator animation) {
mIsScrolling = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mRightToMidAnimator.start();
}
public void leftToMidAnimator(final View runView, boolean anim) {
ObjectAnimator animatorX = ObjectAnimator.ofFloat(runView, "translationX", RUN_X_NEGATIVE, 0);
ObjectAnimator animatorZ = ObjectAnimator.ofFloat(runView, "rotationY", RUN_Y, 0);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(runView, "alpha", LEFT_RIGHT_ALPHA, MIDDLE_ALPHA);
mLeftToMidAnimator = new AnimatorSet();
mLeftToMidAnimator.play(animatorX).with(animatorZ).with(animator3);
if (anim) {
mLeftToMidAnimator.setDuration(DURATION);
} else {
mLeftToMidAnimator.setDuration(0);
}
mLeftToMidAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
mIsScrolling = true;
}
@Override
public void onAnimationEnd(Animator animation) {
mIsScrolling = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mLeftToMidAnimator.start();
}
public void rightToLeftAnimator(View runView, boolean anim) {
ObjectAnimator animator1 = ObjectAnimator.ofFloat(runView, "translationX", RUN_X, RUN_LARGE_X);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(runView, "rotationY", RUN_Y_NEGATIVE, RUN_LARGE_Y_NEGATIVE);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(runView, "alpha", LEFT_RIGHT_ALPHA, 0.0f);
//继续往右偏移
ObjectAnimator animator4 = ObjectAnimator.ofFloat(runView, "translationX", RUN_LARGE_X, RUN_X_NEGATIVE);
ObjectAnimator animator5 = ObjectAnimator.ofFloat(runView, "rotationY", RUN_LARGE_Y_NEGATIVE, RUN_LARGE_Y);
//中途隐藏不显示
ObjectAnimator animator6 = ObjectAnimator.ofFloat(runView, "alpha", 0.0f, 0.0f);
ObjectAnimator animator7 = ObjectAnimator.ofFloat(runView, "translationX", RUN_X_NEGATIVE, RUN_X_NEGATIVE);
//往左偏移显示在左边位置
ObjectAnimator animator8 = ObjectAnimator.ofFloat(runView, "rotationY", RUN_LARGE_Y, RUN_Y);
ObjectAnimator animator9 = ObjectAnimator.ofFloat(runView, "alpha", LEFT_RIGHT_ALPHA, LEFT_RIGHT_ALPHA);
//给分段动画设置时间
if (anim) {
animator1.setDuration(170);
animator4.setDuration(60);
animator7.setDuration(170);
} else {
animator1.setDuration(0);
animator4.setDuration(0);
animator7.setDuration(0);
}
//with:同时执行,after(动画1):在动画1之后执行,befor(动画1):在动画1之前执行。
//请注意以下的after(animator1)。表示动画4.5.6在动画1,2,3执行完毕之后同时执行
mRightToLeftAnimator = new AnimatorSet();
mRightToLeftAnimator.play(animator1).with(animator2).with(animator3);
mRightToLeftAnimator.play(animator4).with(animator5).with(animator6).after(animator1);
mRightToLeftAnimator.play(animator7).with(animator8).with(animator9).after(animator4);
mRightToLeftAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
mIsScrolling = true;
}
@Override
public void onAnimationEnd(Animator animation) {
//mIsScrolling = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mRightToLeftAnimator.start();
}
public void leftToRightAnimator(View runView, boolean anim) {
ObjectAnimator animator1 = ObjectAnimator.ofFloat(runView, "translationX", RUN_X_NEGATIVE, RUN_LARGE_X_NEGATIVE);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(runView, "rotationY", RUN_Y, RUN_LARGE_Y);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(runView, "alpha", LEFT_RIGHT_ALPHA, 0.0f);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(runView, "translationX", RUN_LARGE_X_NEGATIVE, RUN_X);
ObjectAnimator animator5 = ObjectAnimator.ofFloat(runView, "rotationY", RUN_LARGE_Y, RUN_LARGE_Y_NEGATIVE);
ObjectAnimator animator6 = ObjectAnimator.ofFloat(runView, "alpha", 0.0f, 0.0f);
ObjectAnimator animator7 = ObjectAnimator.ofFloat(runView, "translationX", RUN_X, RUN_X);
ObjectAnimator animator8 = ObjectAnimator.ofFloat(runView, "rotationY", RUN_LARGE_Y_NEGATIVE, RUN_Y_NEGATIVE);
ObjectAnimator animator9 = ObjectAnimator.ofFloat(runView, "alpha", LEFT_RIGHT_ALPHA, LEFT_RIGHT_ALPHA);
if (anim) {
animator1.setDuration(170);
animator4.setDuration(60);
animator7.setDuration(170);
} else {
animator1.setDuration(0);
animator4.setDuration(0);
animator7.setDuration(0);
}
mLeftToRightAnimator = new AnimatorSet();
mLeftToRightAnimator.play(animator1).with(animator2).with(animator3);
mLeftToRightAnimator.play(animator4).with(animator5).with(animator6).after(animator1);
mLeftToRightAnimator.play(animator7).with(animator8).with(animator9).after(animator4);
mLeftToRightAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
mIsScrolling = true;
}
@Override
public void onAnimationEnd(Animator animation) {
//mIsScrolling = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mLeftToRightAnimator.start();
}
来源:https://blog.csdn.net/nihenmeila/article/details/121037187


猜你喜欢
- (注意:本文基于JDK1.8)前言任何一个容器类对象用于持有元素后,总是需要遍历元素的,即挨个去访问每个元素1次,而遍历元素,除了常规的依赖
- Java 虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途,如图所示:程序计数器程序计数
- 本文实例展示了DevExpress实现GridView当无数据行时提示消息的方法,具体步骤如下:主要功能代码部分如下:/// <sum
- 场景描述在项目开发的过程中,需要修改调试的时候偶每次都需要重启项目浪费时间,下面是我整理的两种常用的两种方式方式一修改启动配置方式(主要针对
- 本文实例为大家分享了java实现随机数生成器的具体代码,供大家参考,具体内容如下自己编的随机数生成器,比较简陋,功能也单一,当作练手。App
- 使用后台返回验证码图片,验证码存到session中后端实现校验,前端只展示验证码图片。本篇用SpringBoot Thymeleaf实现验证
- 近期用到了一位师兄写的C++程序,总体功能良好。使用不同的数据测试,发现了一个明显的缺点:大数据量下,预处理过程耗时很长。中科院的某计算集群
- 字符串的操作是C#程序设计中十分重要的一个组成部分,本文就以实例形式展现了C#实现移除字符串末尾指定字符的方法。相信对大家学习C#程序设计有
- Kotlin Flow在开发中的常用场景使用大家了解了 Flow 的创建与接收流程,了解 SharedFlow 创建的几种方式,各个参数的用
- xxx cannot be resolved to a type引言 eclipse新导入的项目经常可以
- 本文实例为大家分享了java实现猜数游戏的具体代码,供大家参考,具体内容如下有开始界面,可以设置范围,设置猜的次数代码如下:public s
- 本文实例讲述了Android编程实现将ButtonBar放在屏幕底部的方法。分享给大家供大家参考,具体如下:前面一篇《Android编程实现
- 众所周知在android7.0,修改了对私有存储的限制,导致在获取资源的时候,不能通过Uri.fromFile来获取uri了我们需要适配7.
- 一、简介相信大家用eclipse上的模拟器会觉得很慢很卡,这里给大家介绍个好东西安卓模拟器genymotion。了解更多,可到此网站http
- 光流的概念是由一个叫Gibson的哥们在1950年提出来的。它描述是空间运动物体在观察成像平面上的像素运动的瞬时速度,利用图像序列中像素在时
- 实例如下:/// <summary> /// 上传ftp服务 /// </summary>
- 水仙花数:水仙花数是三位数,它的各位数字的立方和等于这个三位数本身,例如:370=33+73+00;371=33+73+13,370、371
- 前言研究表明,Java堆中对象占据最大比重的就是字符串对象,所以弄清楚字符串知识很重要,本文主要重点聊聊字符串常量池。Java中的字符串常量
- 引言备忘录模式经常可以遇到,譬如下面这些场景:浏览器回退:浏览器一般有浏览记录,当我们在一个网页上点击几次链接之后,可在左上角点击左箭头回退
- C#中List<T>中泛型T如果是一个对象的话,则利用Find函数返回的将是这个对象的指针,对其返回对象的属性进行操作,也会影响