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

本文涉及的产品
视觉智能开放平台,图像通用资源包5000点
视觉智能开放平台,分割抠图1万点
视觉智能开放平台,视频通用资源包5000点
简介: 本文讲述了如何使用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

目录
相关文章
|
4月前
|
Android开发 开发者
Android利用SVG实现动画效果
本文介绍了如何在Android中利用SVG实现动画效果。首先通过定义`pathData`参数(如M、L、Z等)绘制一个简单的三角形SVG图形,然后借助`objectAnimator`实现动态的线条绘制动画。文章详细讲解了从配置`build.gradle`支持VectorDrawable,到创建动画文件、关联SVG与动画,最后在Activity中启动动画的完整流程。此外,还提供了SVG绘制原理及工具推荐,帮助开发者更好地理解和应用SVG动画技术。
203 30
|
4月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
408 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
4月前
|
API Android开发 开发者
Android颜色渐变动画效果的实现
本文介绍了在Android中实现颜色渐变动画效果的方法,重点讲解了插值器(TypeEvaluator)的使用与自定义。通过Android自带的颜色插值器ArgbEvaluator,可以轻松实现背景色的渐变动画。文章详细分析了ArgbEvaluator的核心代码,并演示了如何利用Color.colorToHSV和Color.HSVToColor方法自定义颜色插值器MyColorEvaluator。最后提供了完整的源码示例,包括ColorGradient视图类和MyColorEvaluator类,帮助开发者更好地理解和应用颜色渐变动画技术。
136 3
|
4月前
|
Android开发 开发者
Android SVG动画详细例子
本文详细讲解了在Android中利用SVG实现动画效果的方法,通过具体例子帮助开发者更好地理解和应用SVG动画。文章首先展示了动画的实现效果,接着回顾了之前的文章链接及常见问题(如属性名大小写错误)。核心内容包括:1) 使用阿里图库获取SVG图形;2) 借助工具将SVG转换为VectorDrawable;3) 为每个路径添加动画绑定属性;4) 创建动画文件并关联SVG;5) 在ImageView中引用动画文件;6) 在Activity中启动动画。文末还提供了完整的代码示例和源码下载链接,方便读者实践操作。
263 65
|
2月前
|
安全 数据库 Android开发
在Android开发中实现两个Intent跳转及数据交换的方法
总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
149 11
|
4月前
|
XML Java Maven
Android线条等待动画JMWorkProgress(可添加依赖直接使用)
这是一篇关于Android线条等待动画JMWorkProgress的教程文章,作者计蒙将其代码开源至GitHub,提升可读性。文章介绍了如何通过添加依赖库使用该动画,并详细讲解了XML与Java中的配置方法,包括改变线条颜色、宽度、添加文字等自定义属性。项目已支持直接依赖集成(`implementation &#39;com.github.Yufseven:JMWorkProgress:v1.0&#39;`),开发者可以快速上手实现炫酷的等待动画效果。文末附有GitHub项目地址,欢迎访问并点赞支持!
118 26
|
4月前
|
XML Android开发 数据格式
Android中SlidingDrawer利用透明动画提示效果
本文介绍了在Android中使用`SlidingDrawer`实现带有透明动画提示效果的方法。通过XML布局配置`SlidingDrawer`的把手(handle)和内容(content),结合Activity中的代码实现动态动画效果。最终实现了交互性强、视觉效果良好的滑动抽屉功能。
Android中SlidingDrawer利用透明动画提示效果
|
4月前
|
XML Java Android开发
Android 动画之帧动画 + 补间动画 + 属性动画
本文介绍了Android开发中的三种动画类型:帧动画、补间动画和属性动画。帧动画通过依次播放一系列静态图片实现动态效果,支持Java代码与XML两种实现方式。补间动画基于起始和结束位置自动生成过渡效果,涵盖透明度、位移、旋转、缩放及组合动画等多种形式,并可搭配插值器优化动画过程。属性动画则通过改变对象属性实现动画,支持透明度、位移、旋转、缩放及组合动画,灵活性更高且适用于更复杂的场景。文中提供了详细的代码示例,帮助开发者快速上手。
263 15
|
6月前
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
1224 77
|
3月前
|
安全 Java Android开发
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
170 0
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡