Android开发之使用OpenGL实现翻书动画

本文涉及的产品
视觉智能开放平台,视频资源包5000点
视觉智能开放平台,图像资源包5000点
视觉智能开放平台,分割抠图1万点
简介: 本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。

上一篇文章介绍了如何通过纹理渲染绘制地球仪,当然OpenGL的三维图形处理能力是很强大的,只要善于利用OpenGL,就能很方便地虚拟各种现实生活中的动画效果。本文再来谈谈使用OpenGL实现浏览电子书时候的翻书动画。

博主早期的博文《Android开发笔记(十八)书籍翻页动画》已经介绍了如何通过贝塞尔曲线实现翻书动画的过程,不过该方式展示动画时存在卡顿的现象,并且在书页范围之外还会经常拖着长长的影子,实在是有碍观瞻。现在有了OpenGL,借助三维图形技术能够让翻书动画显得更为平滑、更加逼真。正好博主偶然间淘到了一个外国人写的OpenGL翻书动画,感觉显示效果还不错,故而简单改造了一下贡献出来,方便有需要的朋友。

通过OpenGL描绘三维图形的原理,可参见前面几篇文章,这里就不啰嗦了,下面直接观看使用OpenGL实现翻书动画的效果。

首先是从前往后翻页的效果动画:

gl_turn1.gif

然后是从后往前翻页的效果动画:

gl_turn2.gif

怎么样,还比较流畅吧,其实就是翻书的时候把图片展示为翻卷的立体效果罢了。

具体的Activity实现代码如下所示:

public class GlTurnActivity extends Activity {
   
   
    private final static String TAG = "GlTurnActivity";
    private CurlView cv_content;
    private String[] imgArray = {
   
   "000.jpg", "001.jpg", "002.jpg", "003.jpg"};
    private int cv_height;
    private ArrayList<String> imgList = new ArrayList<String>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gl_turn);
        cv_content = (CurlView) findViewById(R.id.cv_content);
        copyImage();
        showImage();
    }

    // 把图片文件从assets目录复制到SD卡
    private void copyImage() {
   
   
        cv_height = cv_content.getMeasuredHeight();
        String dir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/";
        for (int i=0; i<imgArray.length; i++) {
   
   
            String imgName = imgArray[i];
            String imgPath = dir + imgName;
            AssetsUtil.Assets2Sd(this, imgName, imgPath);
            imgList.add(imgPath);
            if (i == 0) {
   
   
                Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
                cv_height = (int) (bitmap.getHeight() * 1.2);
            }
        }
    }

    // 载入并显示书籍的图片,一开始显示第一页
    private void showImage() {
   
   
        LayoutParams params = cv_content.getLayoutParams();
        params.height = cv_height;
        cv_content.setLayoutParams(params);
        cv_content.setPageProvider(new PageProvider(imgList));
        cv_content.setSizeChangedObserver(new SizeChangedObserver());
        cv_content.setCurrentIndex(0);
        cv_content.setBackgroundColor(Color.LTGRAY);
    }
    // 定义页面的提供者,传入图片文件的路径数组
    private class PageProvider implements CurlView.PageProvider {
   
   
        private ArrayList<String> mPathArray = new ArrayList<String>();

        public PageProvider(ArrayList<String> pathArray) {
   
   
            mPathArray = pathArray;
        }

        @Override
        public int getPageCount() {
   
   
            return mPathArray.size();
        }
        private Bitmap loadBitmap(int width, int height, int index) {
   
   
            Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            b.eraseColor(0xFFFFFFFF);
            Canvas c = new Canvas(b);
            //Drawable d = getResources().getDrawable(mBitmapIds[index]);
            Bitmap image = BitmapFactory.decodeFile(mPathArray.get(index));
            BitmapDrawable d = new BitmapDrawable(getResources(), image);
            int margin = 0;
            int border = 1;
            Rect r = new Rect(margin, margin, width - margin, height - margin);
            int imageWidth = r.width() - (border * 2);
            int imageHeight = imageWidth * d.getIntrinsicHeight() / d.getIntrinsicWidth();
            if (imageHeight > r.height() - (border * 2)) {
   
   
                imageHeight = r.height() - (border * 2);
                imageWidth = imageHeight * d.getIntrinsicWidth() / d.getIntrinsicHeight();
            }
            r.left += ((r.width() - imageWidth) / 2) - border;
            r.right = r.left + imageWidth + border + border;
            r.top += ((r.height() - imageHeight) / 2) - border;
            r.bottom = r.top + imageHeight + border + border;
            Paint p = new Paint();
            p.setColor(0xFFC0C0C0);
            c.drawRect(r, p);
            r.left += border;
            r.right -= border;
            r.top += border;
            r.bottom -= border;
            d.setBounds(r);
            d.draw(c);
            return b;
        }
        @Override
        public void updatePage(CurlPage page, int width, int height, int index) {
   
   
            Bitmap front = loadBitmap(width, height, index);
            page.setTexture(front, CurlPage.SIDE_BOTH);
        }
    }
    // 定义书籍尺寸的变化监听器
    private class SizeChangedObserver implements CurlView.SizeChangedObserver {
   
   
        @Override
        public void onSizeChanged(int w, int h) {
   
   
            cv_content.setViewMode(CurlView.SHOW_ONE_PAGE);
            cv_content.setMargins(0f, 0f, 0f, 0f);
        }
    }
}

完整的工程代码见博主的github,该工程的demo地址为 https://github.com/aqi00/note/tree/master/ExmOpenGL

目录
相关文章
|
12天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
38 19
|
12天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
37 14
|
15天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
|
13天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
在数字时代,掌握安卓应用开发技能是进入IT行业的关键。本文将引导读者从零基础开始,逐步深入安卓开发的世界,通过实际案例和代码示例,展示如何构建自己的第一个安卓应用。我们将探讨基本概念、开发工具设置、用户界面设计、数据处理以及发布应用的全过程。无论你是编程新手还是有一定基础的开发者,这篇文章都将为你提供宝贵的知识和技能,帮助你在安卓开发的道路上迈出坚实的步伐。
25 5
|
11天前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
|
13天前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
12天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
16天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
12天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
21 0
|
16天前
|
存储 监控 Java
探索安卓开发:从基础到进阶的旅程
在这个数字时代,移动应用已成为我们日常生活的一部分。对于开发者来说,掌握安卓开发不仅是技能的提升,更是通往创新世界的钥匙。本文将带你了解安卓开发的核心概念,从搭建开发环境到实现复杂功能,逐步深入安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的见解和技巧,帮助你在安卓开发的道路上更进一步。
18 0