Android 仿掌阅 小说阅读器 书籍打开动画
搜了半天 终于找到关键字 掌阅 . ireader 可惜放到项目炸了,,,,
完整代码
// 万能适配器compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.50'implementation 'com.android.support:design:28.0.0'
maven { url "https://jitpack.io" }
item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_weight="1"android:gravity="center"android:layout_width="match_parent"android:layout_height="wrap_content"><ImageViewandroid:layout_margin="20dp"android:id="@+id/iv"android:scaleType="fitXY"android:src="@mipmap/ic_launcher"android:layout_width="50dp"android:layout_height="50dp"/></LinearLayout>
public class MyAdapter extends BaseQuickAdapter<String, BaseViewHolder> {public MyAdapter(int layoutResId, @Nullable List<String> data) {super(layoutResId, data);}@Overrideprotected void convert(@NonNull BaseViewHolder helper, String item) {}
}
public class ContentScaleAnimation extends Animation {private float mPivotX;private float mPivotY;private float mPivotXValue; // 控件左上角Xprivate float mPivotYValue;private final float scaleTimes;private boolean mReverse;public ContentScaleAnimation(float mPivotXValue, float mPivotYValue, float scaleTimes, boolean mReverse) {this.mPivotXValue = mPivotXValue;this.mPivotYValue = mPivotYValue;this.scaleTimes = scaleTimes;this.mReverse = mReverse;}@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {Matrix matrix=t.getMatrix();//缩放方法if (mReverse) {matrix.postScale(1 + (scaleTimes - 1) * (1.0f - interpolatedTime), 1 + (scaleTimes - 1) * (1.0f - interpolatedTime), mPivotX - mPivotXValue, mPivotY - mPivotYValue);} else {// matrix.postScale(1 + (scaleTimes - 1) * interpolatedTime, 1 + (scaleTimes - 1) * interpolatedTime, mPivotX, mPivotY);matrix.postScale(1 + (scaleTimes - 1) * interpolatedTime, 1 + (scaleTimes - 1) * interpolatedTime, mPivotX - mPivotXValue , mPivotY - mPivotYValue );}float a = mPivotX - mPivotXValue;float b = mPivotY - mPivotYValue;// Log.d("scaleAnimation","mPivotX - mPivotXValue ="+a);// Log.d("scaleAnimation","mPivotY - mPivotYValue ="+b);}//缩放点坐标值@Overridepublic void initialize(int width, int height, int parentWidth, int parentHeight) {super.initialize(width, height, parentWidth, parentHeight);mPivotX = resolvePivotX(mPivotXValue, parentWidth, width);mPivotY = resolvePivoY(mPivotYValue, parentHeight, height);// Log.d("scaleAnimation","mPivotX is"+mPivotX);// Log.d("scaleAnimation","mPivotY is"+mPivotY);// Log.d("scaleAnimation","mPivotXValue is"+mPivotXValue);// Log.d("scaleAnimation","mPivotYValue is"+mPivotYValue);// Log.d("scaleAnimation","width ="+width);// Log.d("scaleAnimation","width ="+height);// Log.d("scaleAnimation","width ="+parentWidth);// Log.d("scaleAnimation","width ="+parentHeight);}//缩放点坐标值 缩放点到自身左边距离/缩放点到父控件左边的距离=缩放点自身右侧距离/缩放点到父控件右边的距离private float resolvePivotX(float margingLeft, int parentWidth, int width) {return (margingLeft * parentWidth) / (parentWidth - width);}private float resolvePivoY(float marginTop, int parentHeight, int height) {return (marginTop * parentHeight) / (parentHeight - height);}public void reverse() {mReverse = !mReverse;}public boolean getMReverse() {return mReverse;}public void setmPivotXValue (float mPivotXValue1) {this.mPivotXValue = mPivotXValue1;}public void setmPivotYValue (float mPivotYValue1) {this.mPivotYValue = mPivotYValue1;}
}
public class Rotate3DAnimation extends Animation {private Camera mCamera;private final float mFromDegrees;private final float mToDegrees;private float mPivotXValue;// 控件左上角Xprivate float mPivotYValue;//private final float mDepthZ; //不需要用到此参数private final float scaleTimes;private boolean mReverse;private float mPivotX; //缩放点Xprivate float mPivotY; //缩放点Y/*** cover 动画构造方法,一边放大,一边翻转* @param mFromDegrees* @param mToDegrees* @param mPivotXValue 控件左上角X* @param mPivotYValue 控件左上角Y* @param scaleTimes 缩放比例* @param mReverse 动画是否逆向进行*/public Rotate3DAnimation(float mFromDegrees, float mToDegrees, float mPivotXValue, float mPivotYValue, float scaleTimes, boolean mReverse) {this.mFromDegrees = mFromDegrees;this.mToDegrees = mToDegrees;this.mPivotXValue = mPivotXValue;this.mPivotYValue = mPivotYValue;this.scaleTimes = scaleTimes;this.mReverse = mReverse;}@Overridepublic void initialize(int width, int height, int parentWidth, int parentHeight) {super.initialize(width, height, parentWidth, parentHeight);mCamera = new Camera();mPivotX = resolvePivotX(mPivotXValue, parentWidth, width); //计算缩放点XmPivotY = resolvePivoY(mPivotYValue, parentHeight, height); //计算缩放点Y}/*** 执行顺序 matrix.preTranslate() --> camera.rotateY(degrees) --> matrix.postTranslate() --> matrix.postScale()* @param interpolatedTime* @param t*/@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {float degrees = mReverse ? mToDegrees + (mFromDegrees - mToDegrees) * interpolatedTime : mFromDegrees + (mToDegrees - mFromDegrees) * interpolatedTime;final Matrix matrix = t.getMatrix();final Camera camera = mCamera;camera.save();camera.rotateY(degrees);camera.getMatrix(matrix);camera.restore();// matrix.preTranslate(-mPivotXValue, 0); //在进行rotateY之前需要移动物体,让物体左边与Y轴对齐// matrix.postTranslate(mPivotXValue, 0); //还原物体位置if (mReverse) {matrix.postScale(1 + (scaleTimes - 1) * (1.0f - interpolatedTime), 1 + (scaleTimes - 1) * (1.0f - interpolatedTime), mPivotX - mPivotXValue , mPivotY - mPivotYValue);} else {// matrix.postScale(1 + (scaleTimes - 1) * interpolatedTime, 1 + (scaleTimes - 1) * interpolatedTime, mPivotX, mPivotY);matrix.postScale(1 + (scaleTimes - 1) * interpolatedTime, 1 + (scaleTimes - 1) * interpolatedTime, mPivotX - mPivotXValue , mPivotY - mPivotYValue );}}private float resolvePivotX(float margingLeft, int parentWidth, int width) {return (margingLeft * parentWidth) / (parentWidth - width);}private float resolvePivoY(float marginTop, int parentHeight, int height) {return (marginTop * parentHeight) / (parentHeight - height);}public void reverse() {mReverse = !mReverse;}public boolean getMReverse() {return mReverse;}public void setmPivotXValue (float mPivotXValue1) {this.mPivotXValue = mPivotXValue1;}public void setmPivotYValue (float mPivotYValue1) {this.mPivotYValue = mPivotYValue1;}
}
public class Main2Activity extends AppCompatActivity implements Animation.AnimationListener {private int[] location = new int[2];private ContentScaleAnimation contentAnimation;private Rotate3DAnimation coverAnimation;private boolean mIsOpen = false;private int animationCount = 0; //动画加载计数器 0 默认 1一个动画执行完毕 2二个动画执行完毕private AbsoluteLayout wmRootView;private WindowManager mWindowManager;private View rootView;private ImageView content;private TextView cover;private View iv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main2);mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);wmRootView = new AbsoluteLayout(this);rootView = getWindow().getDecorView();initRecycler();}private void initRecycler() {List<String> list = new ArrayList<>();for (int i = 0; i < 20; i++) {list.add(" " + i);}MyAdapter myAdapter = new MyAdapter(R.layout.item_iv, list);RecyclerView recycler = findViewById(R.id.recycler);recycler.setAdapter(myAdapter);recycler.setLayoutManager(new GridLayoutManager(this, 3));myAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {@Overridepublic void onItemClick(BaseQuickAdapter adapter, View view, int position) {iv = view.findViewById(R.id.iv);iv.getLocationInWindow(location);mWindowManager.addView(wmRootView, getDefaultWindowParams());content = new ImageView(Main2Activity.this);content.setBackgroundColor(getResources().getColor(R.color.colorPrimary));cover = new TextView(getApplicationContext());cover.setBackgroundResource(R.mipmap.ic_launcher);AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams(iv.getLayoutParams());params.x = location[0];params.y = location[1];wmRootView.addView(content, params);wmRootView.addView(cover, params);initAnimation();if (contentAnimation.getMReverse()) {contentAnimation.reverse();}if (coverAnimation.getMReverse()) {coverAnimation.reverse();}cover.clearAnimation();cover.startAnimation(coverAnimation);content.clearAnimation();content.startAnimation(contentAnimation);}});}private void initAnimation() {AccelerateInterpolator interpolator = new AccelerateInterpolator();float scale1 = rootView.getWidth() / (float) iv.getMeasuredWidth();float scale2 = rootView.getHeight() / (float) iv.getMeasuredHeight();float scaleTimes = scale1 > scale2 ? scale1 : scale2; //计算缩放比例contentAnimation = new ContentScaleAnimation(location[0], location[1], scaleTimes, false);contentAnimation.setInterpolator(interpolator); //设置插值器contentAnimation.setDuration(1000);contentAnimation.setFillAfter(true); //动画停留在最后一帧contentAnimation.setAnimationListener(this);coverAnimation = new Rotate3DAnimation(0, -180, location[0], location[1], scaleTimes, false);coverAnimation.setInterpolator(interpolator);coverAnimation.setDuration(1000);coverAnimation.setFillAfter(true);coverAnimation.setAnimationListener(this);}private WindowManager.LayoutParams getDefaultWindowParams() {WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.MATCH_PARENT,0, 0,WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,//windown类型,有层级的大的层级会覆盖在小的层级WindowManager.LayoutParams.FLAG_FULLSCREEN,PixelFormat.RGBA_8888);return params;}@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {//有两个动画监听会执行两次,所以要判断if (!mIsOpen) {animationCount++;if (animationCount >= 2) {mIsOpen = true;Intent intent = new Intent();intent.setClass(Main2Activity.this, MainActivity.class);startActivity(intent);overridePendingTransition(android.support.v7.appcompat.R.anim.abc_grow_fade_in_from_bottom, android.support.v7.appcompat.R.anim.abc_shrink_fade_out_from_bottom);}} else {animationCount--;if (animationCount <= 0) {mIsOpen = false;wmRootView.removeView(content);mWindowManager.removeView(wmRootView);}}}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overrideprotected void onRestart() {closeBookAnimation();super.onRestart();}public void closeBookAnimation() {if (mIsOpen && wmRootView != null) {//因为书本打开后会移动到第一位置,所以要设置新的位置参数contentAnimation.setmPivotXValue(location[0]);contentAnimation.setmPivotYValue(location[1]);coverAnimation.setmPivotXValue(location[0]);coverAnimation.setmPivotYValue(location[1]);AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams(iv.getLayoutParams());params.x = location[0];params.y = location[1];//firstLocation[1]在滑动的时候回改变,所以要在dispatchDraw的时候获取该位置值wmRootView.updateViewLayout(cover, params);wmRootView.updateViewLayout(content, params);//动画逆向运行if (!contentAnimation.getMReverse()) {contentAnimation.reverse();}if (!coverAnimation.getMReverse()) {coverAnimation.reverse();}//清除动画再开始动画content.clearAnimation();content.startAnimation(contentAnimation);cover.clearAnimation();cover.startAnimation(coverAnimation);}}
}
Android 仿掌阅 小说阅读器 书籍打开动画相关推荐
- 仿掌阅实现书籍打开动画
一. 前言 上次打开掌阅的时候看到书籍打开动画的效果还不错,正好最近也在做阅读器的项目,所以想在项目中实现一下. 二. 思路 讲思路之前,先看一下实现效果吧: 书籍打开关闭动画.gif 看完实现效果, ...
- android 上下滚动文字_计算机毕设项目004之Android系统在线小说阅读器
计算机毕设项目004之Android系统在线小说阅读器 一. 项目名称 基于Android系统的在线小说阅读器 二. 项目简介 项目中的角色功能: 支持翻页动画:仿真翻页.覆盖翻页.上下滚动翻页等翻页 ...
- android优化中国风应用、完整NBA客户端、动态积分效果、文件传输、小说阅读器等源码...
Android精选源码 android拖拽下拉关闭效果源码 一款优雅的中国风Android App源码 EasySignSeekBar一个漂亮而强大的自定义view15 android仿蘑菇街,蜜芽宝 ...
- 免费小说阅读器(Android版本)全站开源
此小说阅读器只追求两项 极简(无广告,无添加) 丰富(内容丰富,只有你想不到的,没有它没有的) 漫品客户端 全站开源 开源地址: https://github.com/AnyMarvel/ManPin ...
- Android小说阅读器
这是早期做的一个 android小说阅读器项目,是本地阅读器,没有联网功能,目前只支持txt格式. 但项目功能是比较齐全的: 文件预览 导入书籍 创建分类 批量管理书架上的图书 小说阅读 查看书籍目录 ...
- 基于Android的看小说APP源码Android本科毕业设计Android小说阅读器、小说APP源码
基于kotlin + 协程 + MVVM 模式来编写的看小说APP. 完整代码下载地址:基于Android的看小说APP源码Android本科毕业设计Android小说阅读器.小说APP源码 主要框架 ...
- android txt小说阅读器的实现
一分钟让你的app快速集成漂亮简洁的小说阅读器!!请进: https://github.com/bifan-wei/HwTxtReader 2021-06-12更新,适配Android X! 目前实现 ...
- PC免费简约开源的TXT小说阅读器(提取章节、书籍分组管理、记忆阅读进度、换肤、换字体、换主题)仅支持Windows
最近自己做了个小说阅读器,就是下面这个东西啦,目前仅支持Window系统 个人喜欢在电脑.平板上等大屏幕设备上阅读小说或电子书籍.原因其一是屏幕足够大,可以选择更舒服的字体大小:其二是觉得小屏幕看字体 ...
- android 阅读器自动滚动,Android编程实现小说阅读器滑动效果的方法
本文实例讲述了Android编程实现小说阅读器滑动效果的方法.分享给大家供大家参考,具体如下: 看过小说都知道小说阅读器翻页有好多种效果,比如仿真翻页,滑动翻页,等等.由于某种原因,突然想写一个简单点 ...
最新文章
- 【Linux】数据库管理
- 织梦dedecms如何对列表添加判断语句
- Foundation框架
- 数据结构:排序算法之堆排序和选择排序
- STM32H743+CubeMX-双路FDCAN同时工作的终极方案(裸机)
- java 滚动显示信息_滚动显示文本的Java程序
- mysql 5.7.10免安装_免安装版mysql5.7.10-16配置教程(2)
- php替换图片_php实现图片上传并进行替换操作
- MacOS入门技巧分享
- PHP substr(),mb_substr(),mb_strcut()比较
- VMware解决黑屏
- 查询mysql表的所有字段名_查询数据库中所有表名,查询表中所有字段名
- 弯头lisp_(最全的)管道材料代号说明
- 在麒麟桌面操作系统编译安装postgresql的经历
- 360全景拼接 opencv_GitHub - hellojiawa/AndroidPanoDemo: 使用Opencv全景照片拼接
- Vue + Element UI 实现权限管理系统(更换皮肤主题)
- 两个L组成的括号?(取整符号)
- python技术线上培训
- 学生类定义(类和对象) Python
- 狂赚 1200 亿,差点收购苹果,影响千万程序员,那个叫做太阳的公司却陨落了!...
热门文章
- 【Graphormer阅读笔记、实验与刷榜】《Do Transformers Really Perform Bad for Graph Representation?》
- 【编码】csv文件打开是乱码
- shopify订单管理软件,获取订单方法
- SEO优化之充分理解“四处一词”
- 中值联认证中心发布的区块链证书验证真伪的办法
- excel功能小技巧:自动求和的注意事项
- win7 64 系统中打开或关闭windows功能空白
- argument type mismatch 参数类型不匹配
- android中实现毛笔效果(View 中绘图)
- nodejs在windows下安装后npm命令无法使用的解决方法