当前位置:   article > 正文

Android App开发手机阅读中实现平滑翻书效果和卷曲翻书动画实战(附源码 简单易懂 可直接使用)_android 翻书效果

android 翻书效果

需要图片集和源码请点赞关注收藏后评论区留言~~~

一、平滑翻书效果

与纸质书籍类似,手机上的电子书也有很多页,逐页浏览可采用翻页视图,然而翻页视图犹如一幅从左到右的绵长画卷,与现实生活中上下层叠的书籍并不相像,若想让手机电子书更贴近纸质书的阅读体验,就需要重新设计上下翻动的视图。书页应该具备以下视图特征

1:能够容纳图片在内的多个控件,意味着自定义视图必须由某种布局派生而来

2:书页存在两种状态 未遮挡时的高亮状态 被遮挡时的阴影状态

3:鉴于书页允许拉动 考虑给它设置左侧间距 左侧间距为零时 该页完整显示 左侧检测为负值时 该页向左缩进

效果如下图 连接真机测试食用效果更佳~~~ 

 

 

 

代码如下

Java类 

  1. package com.example.ebook;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import androidx.appcompat.widget.Toolbar;
  4. import androidx.viewpager.widget.PagerTabStrip;
  5. import androidx.viewpager.widget.ViewPager;
  6. import android.app.ProgressDialog;
  7. import android.content.Intent;
  8. import android.os.Bundle;
  9. import android.text.TextUtils;
  10. import android.util.Log;
  11. import android.util.TypedValue;
  12. import android.view.Menu;
  13. import android.view.MenuItem;
  14. import com.example.ebook.adapter.PdfPageAdapter;
  15. import com.example.ebook.dao.BookDao;
  16. import com.example.ebook.entity.BookInfo;
  17. import com.example.ebook.util.AssetsUtil;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. public class PdfRenderActivity extends AppCompatActivity {
  21. private final static String TAG = "PdfRenderActivity";
  22. private List<String> mPathList = new ArrayList<>(); // 图片路径列表
  23. private String mFileName = "tangshi.pdf"; // 演示文件的名称
  24. private ViewPager vp_content; // 声明一个翻页视图对象
  25. private BookDao bookDao; // 声明一个书籍的持久化对象
  26. private ProgressDialog mDialog; // 声明一个进度对话框对象
  27. @Override
  28. protected void onCreate(Bundle savedInstanceState) {
  29. super.onCreate(savedInstanceState);
  30. setContentView(R.layout.activity_pdf_render);
  31. initView(); // 初始化视图
  32. // 从App实例中获取唯一的书籍持久化对象
  33. bookDao = MainApplication.getInstance().getBookDB().bookDao();
  34. // 弹出进度对话框
  35. mDialog = ProgressDialog.show(this, "请稍候", "正在努力加载");
  36. new Thread(() -> importPDF()).start(); // 启动pdf文件的导入线程
  37. }
  38. // 初始化视图
  39. private void initView() {
  40. String title = "";
  41. // 从前个页面传来的数据中获取书籍的标题和文件名称
  42. if (getIntent().getExtras()!=null && !getIntent().getExtras().isEmpty()) {
  43. title = getIntent().getStringExtra("title");
  44. mFileName = getIntent().getStringExtra("file_name");
  45. }
  46. Toolbar tl_head = findViewById(R.id.tl_head);
  47. tl_head.setTitle(!TextUtils.isEmpty(title) ? title : mFileName);
  48. setSupportActionBar(tl_head); // 替换系统自带的ActionBar
  49. // 设置工具栏左侧导航图标的点击监听器
  50. tl_head.setNavigationOnClickListener(view -> finish());
  51. vp_content = findViewById(R.id.vp_content);
  52. PagerTabStrip pts_tab = findViewById(R.id.pts_tab);
  53. // 设置翻页标题栏的文本大小
  54. pts_tab.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);
  55. }
  56. // 从指定的资产文件导入pdf文件
  57. private void importPDF() {
  58. mPathList = AssetsUtil.getPathListFromPdf(this, mFileName);
  59. Log.d(TAG, "mPathList.size="+mPathList.size());
  60. BookInfo book = bookDao.queryBookByName(mFileName);
  61. if (book != null) {
  62. book.setPageCount(mPathList.size());
  63. bookDao.updateBook(book); // 更新数据库中该书籍记录的总页数
  64. }
  65. // 回到主线程显示导入后的pdf各页面
  66. runOnUiThread(() -> {
  67. PdfPageAdapter adapter = new PdfPageAdapter(getSupportFragmentManager(), mPathList);
  68. vp_content.setAdapter(adapter);
  69. if (mDialog != null && mDialog.isShowing()) {
  70. mDialog.dismiss(); // 关闭进度对话框
  71. }
  72. });
  73. }
  74. // 在创建选项菜单时调用
  75. @Override
  76. public boolean onCreateOptionsMenu(Menu menu) {
  77. getMenuInflater().inflate(R.menu.menu_book, menu);
  78. return true;
  79. }
  80. // 在选中菜单项时调用
  81. @Override
  82. public boolean onOptionsItemSelected(MenuItem item) {
  83. if (item.getItemId() == R.id.menu_slide) { // 点击了“平滑翻页”
  84. Intent intent = new Intent(this, PdfSlideActivity.class);
  85. intent.putExtra("file_name", mFileName);
  86. startActivity(intent);
  87. } else if (item.getItemId() == R.id.menu_curve) { // 点击了“卷曲翻页”
  88. Intent intent = new Intent(this, PdfCurveActivity.class);
  89. intent.putExtra("file_name", mFileName);
  90. startActivity(intent);
  91. } else if (item.getItemId() == R.id.menu_opengl) { // 点击了“OpenGL翻页”
  92. Intent intent = new Intent(this, PdfOpenglActivity.class);
  93. intent.putExtra("file_name", mFileName);
  94. startActivity(intent);
  95. }
  96. return super.onOptionsItemSelected(item);
  97. }
  98. }

XML文件

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:app="http://schemas.android.com/apk/res-auto"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical">
  6. <androidx.appcompat.widget.Toolbar
  7. android:id="@+id/tl_head"
  8. android:layout_width="match_parent"
  9. android:layout_height="50dp"
  10. android:background="@color/blue_light"
  11. app:navigationIcon="@drawable/icon_back" />
  12. <com.example.ebook.widget.ViewSlider
  13. android:id="@+id/vs_content"
  14. android:layout_width="match_parent"
  15. android:layout_height="wrap_content" />
  16. </LinearLayout>

二、实现卷曲翻书动画

前面介绍的平滑翻书固然实现了层叠翻页,可是该方式依然无法模拟现实生活中的翻书动画,现实当中每翻过一页,手指捏住书页的右下角,然后轻轻的往左上方翻,可以看出翻书的效果映射到平面上可以划分为三个区域,A区域为当前正在翻的页面,B区域为当前页的背面,C区域为露出来的下一页。

鉴于贝塞尔曲线的柔韧特性,可将其应用于翻书时的卷曲线条,其中直线通过首位两个端点连接起来 

至此 翻书效果还剩下两个功能点有待实现 说明如下

1:在手指触摸的过程中 要实时计算各个坐标点的位置 并调整书页的画面绘制

2:手指松开之后 要判断接下来是往前翻页还是往后缩回去,并在前翻与后缩的过程中展示翻书动画

第二点可以借助滚动其Scroller实现,第一点则需要重写onTouchEvent方法,分别处理手指按下,易懂,松开三种情况的视图变迁

实现效果如下 连接真机测试效果更佳

 

 

 

 代码如下

Java类

  1. package com.example.ebook;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import androidx.appcompat.widget.Toolbar;
  4. import android.graphics.Bitmap;
  5. import android.graphics.BitmapFactory;
  6. import android.os.Bundle;
  7. import android.os.Handler;
  8. import android.os.Looper;
  9. import android.text.TextUtils;
  10. import android.util.Log;
  11. import android.view.ViewGroup;
  12. import com.example.ebook.util.AssetsUtil;
  13. import com.example.ebook.util.Utils;
  14. import com.example.ebook.widget.CurveView;
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. public class PdfCurveActivity extends AppCompatActivity {
  18. private final static String TAG = "PdfCurveActivity";
  19. private CurveView cv_book; // 声明一个卷曲视图对象
  20. private List<String> mPathList = new ArrayList<>(); // 图片路径列表
  21. private String mFileName = "tangshi.pdf"; // 演示文件的名称
  22. @Override
  23. protected void onCreate(Bundle savedInstanceState) {
  24. super.onCreate(savedInstanceState);
  25. setContentView(R.layout.activity_pdf_curve);
  26. initView(); // 初始化视图
  27. // 加载pdf会花一点点时间,这里先让整个界面出来,再慢慢渲染pdf
  28. new Handler(Looper.myLooper()).post(() -> renderPDF());
  29. }
  30. // 初始化视图
  31. private void initView() {
  32. String title = "";
  33. // 从前个页面传来的数据中获取书籍的标题和文件名称
  34. if (getIntent().getExtras()!=null && !getIntent().getExtras().isEmpty()) {
  35. title = getIntent().getStringExtra("title");
  36. mFileName = getIntent().getStringExtra("file_name");
  37. }
  38. Toolbar tl_head = findViewById(R.id.tl_head);
  39. tl_head.setTitle(!TextUtils.isEmpty(title) ? title : mFileName);
  40. // 设置工具栏左侧导航图标的点击监听器
  41. tl_head.setNavigationOnClickListener(view -> finish());
  42. cv_book = findViewById(R.id.cv_book);
  43. findViewById(R.id.btn_resume).setOnClickListener(v -> cv_book.reset());
  44. }
  45. // 开始渲染PDF文件
  46. private void renderPDF() {
  47. // 把资产文件转换为图片路径列表
  48. mPathList = AssetsUtil.getPathListFromPdf(this, mFileName);
  49. Log.d(TAG, "mPathList.size="+mPathList.size());
  50. Bitmap first = BitmapFactory.decodeFile(mPathList.get(0));
  51. int height = (int)(1.0*first.getHeight()/first.getWidth() * Utils.getScreenWidth(this));
  52. Log.d(TAG, "height="+height);
  53. ViewGroup.LayoutParams params = cv_book.getLayoutParams();
  54. params.height = height; // 根据书页图片的尺寸调整卷曲视图的高度
  55. cv_book.setLayoutParams(params); // 设置卷曲视图的布局参数
  56. cv_book.setFilePath(mPathList); // 设置卷曲视图的文件路径
  57. }
  58. }

XML文件

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:app="http://schemas.android.com/apk/res-auto"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical">
  6. <androidx.appcompat.widget.Toolbar
  7. android:id="@+id/tl_head"
  8. android:layout_width="match_parent"
  9. android:layout_height="50dp"
  10. android:background="@color/blue_light"
  11. app:navigationIcon="@drawable/icon_back" />
  12. <Button
  13. android:id="@+id/btn_resume"
  14. android:layout_width="match_parent"
  15. android:layout_height="wrap_content"
  16. android:text="恢复原状"
  17. android:textColor="@color/black"
  18. android:textSize="17sp"
  19. android:visibility="gone" />
  20. <com.example.ebook.widget.CurveView
  21. android:id="@+id/cv_book"
  22. android:layout_width="match_parent"
  23. android:layout_height="wrap_content" />
  24. </LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/267566
推荐阅读
相关标签
  

闽ICP备14008679号