Android OpenGL动态壁纸

本文介绍如何使用OpenGL ES开发Android动态壁纸,包括创建WallpaperService、定制GLSurfaceView及实现随主屏幕滚动的背景效果等关键技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android OpenGL动态壁纸

首先申明下,本文为笔者学习《OpenGL ES应用开发实践指南》的笔记,并加入笔者自己的理解和归纳总结。

1、动态壁纸的Service组件

WallpaperService提供了基本的动态壁纸的实现。
public class GLWallpaperService extends WallpaperService {

    @Override
    public Engine onCreateEngine() {
        return new GLEngine();
    }

}

2、创建自定义GLSurfaceView

GLSurfaceView会调用getHolder()来添加界面,只需重载getHolder方法,返回动态壁纸的渲染表面。onWallpaperDestroy在销毁动态壁纸时被调用,使用GLSurfaceView的onDetachedFromWindow方法。
class WallpaperGLSurfaceView extends GLSurfaceView {

	public WallpaperGLSurfaceView(Context context) {
		super(context);
	}

	@Override
	public SurfaceHolder getHolder() {
		return GLEngine.this.getSurfaceHolder();
	}

	public void onWallpaperDestroy() {
		super.onDetachedFromWindow();
	}
}

3、Engine类

GLEngine继承Engine类,当动态壁纸创建时,调用GLEngine的onCreate方法来初始化,销毁时调用onDestroy方法。当动态壁纸可见或者隐藏时,onVisibilityChanged方法会被调用。
public class GLEngine extends Engine {
	@Override
	public void onCreate(SurfaceHolder surfaceHolder) {
		super.onCreate(surfaceHolder);
	}

	@Override
	public void onVisibilityChanged(boolean visible) {
		super.onVisibilityChanged(visible);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
	}

}
完善动态壁纸的生命周期,在onCreate中创建GLSurfaceView,onDestroy中销毁。
private WallpaperGLSurfaceView mSurfaceView;
		
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
	super.onCreate(surfaceHolder);

	mSurfaceView = new WallpaperGLSurfaceView(GLWallpaperService.this);
}
	
public void onVisibilityChanged(boolean visible) {
	super.onVisibilityChanged(visible);

	if (mRender) {
		if (visible) {
			mSurfaceView.onResume();
		} else {
			mSurfaceView.onPause();
		}
	}
}

@Override
public void onDestroy() {
	super.onDestroy();

	mSurfaceView.onWallpaperDestroy();
}

4、添加配置

在AndroidManifest.xml中添加
<uses-feature android:name="android.software.live_wallpaper" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
表明这个应用包含一个动态壁纸,并且还需要OpenGL ES 2.0或以上版本。
还需要添加动态壁纸Service的引用
<service android:name=".opengl.GLWallpaperService"
	android:label="@string/app_name"
	android:permission="android.permission.BIND_WALLPAPER" >
	<intent-filter>
		<action android:name="android.service.wallpaper.WallpaperService" />
	</intent-filter>
	<meta-data
		android:name="android.service.wallpaper"
		android:resource="@xml/wallpaper" />
</service>
在资源目录res/xml下,添加wapaper.xml文件
<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
    android:thumbnail="@drawable/ic_wallpaper" />

5、体验动态壁纸

(1) 切换到设备的主屏幕上,按住屏幕的空白部分,直至弹出一个菜单。
(2) 选择"动态壁纸",从弹出的列表中选择我们自己的动态壁纸。
(3) 选择"设置壁纸"


6、随主屏幕滚动背景

当你在主屏幕上的不同页面之间来回滑动时,动态壁纸没有移动,通过Engine的onOffsetsChanged方法,可以是实现动态壁纸的滚动效果。
public void onOffsetsChanged(final float xOffset, final float yOffset, float xOffsetStep,
							 float yOffsetStep, int xPixelOffset, int yPixelOffset) {
	mSurfaceView.queueEvent(new Runnable() {
		@Override
		public void run() {
			mShaderRender.handleOffsetsChanged(xOffset, yOffset);
		}
	});
}

7、GLWallpaperService类

public class GLWallpaperService extends WallpaperService {

    @Override
    public Engine onCreateEngine() {
        return new GLEngine();
    }

    public class GLEngine extends Engine {
        private WallpaperGLSurfaceView mSurfaceView;
        private OpenGLParticleShaderRender mShaderRender;
        private boolean mRender;

        @Override
        public void onCreate(SurfaceHolder surfaceHolder) {
            super.onCreate(surfaceHolder);

            mSurfaceView = new WallpaperGLSurfaceView(GLWallpaperService.this);

            ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
            ConfigurationInfo configurationInfo = am.getDeviceConfigurationInfo();

            boolean supportEs2 = configurationInfo.reqGlEsVersion >= 0x20000;

            if (supportEs2) {
                // 选择OpenGL ES 2.0
                mSurfaceView.setEGLContextClientVersion(2);
                mShaderRender = new OpenGLParticleShaderRender();
                // 设置渲染
                mSurfaceView.setRenderer(mShaderRender);
                mRender = true;
            } else {
                Toast.makeText(GLWallpaperService.this ,
                        "This device does not support OpenGL ES 2.0",
                        Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            super.onVisibilityChanged(visible);

            if (mRender) {
                if (visible) {
                    mSurfaceView.onResume();
                } else {
                    mSurfaceView.onPause();
                }
            }
        }

        @Override
        public void onDestroy() {
            super.onDestroy();

            mSurfaceView.onWallpaperDestroy();
        }

        @Override
        public void onOffsetsChanged(final float xOffset, final float yOffset, float xOffsetStep,
                                     float yOffsetStep, int xPixelOffset, int yPixelOffset) {
            mSurfaceView.queueEvent(new Runnable() {
                @Override
                public void run() {
                    LogUtil.log("GLEngine", "xOffset = " + xOffset + ", yOffset = " + yOffset);
                    mShaderRender.handleOffsetsChanged(xOffset, yOffset);
                }
            });
        }

        class WallpaperGLSurfaceView extends GLSurfaceView {

            public WallpaperGLSurfaceView(Context context) {
                super(context);
            }

            @Override
            public SurfaceHolder getHolder() {
                return GLEngine.this.getSurfaceHolder();
            }

            public void onWallpaperDestroy() {
                super.onDetachedFromWindow();
            }
        }

    }

    private class OpenGLParticleShaderRender implements GLSurfaceView.Renderer {
        private Particle mParticle;
        private ParticleProgram mParticleProgram;
        private ParticleShooter mRedParticleShooter, mGreenParticleShooter, mBlueParticleShooter;
        private long mGlobalStartTime;

        private float[] projectionMatrix = new float[16];
        private float[] viewMatrix = new float[16];
        private float[] viewProjectionMatrix = new float[16];

        private float xOffset, yOffset;

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.1f);

            GLES20.glEnable(GLES20.GL_BLEND);
            GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);

            mParticleProgram = new ParticleProgram(GLWallpaperService.this);
            mParticle = new Particle(10000);

            mGlobalStartTime = System.nanoTime();

            final Geometry.Vector particleDirection = new Geometry.Vector(0f, 0.5f, 0f);

            mRedParticleShooter = new ParticleShooter(new Geometry.Point(-1, 0, 0),
                    particleDirection, Color.rgb(250, 50, 5));

            mGreenParticleShooter = new ParticleShooter(new Geometry.Point(0, 0, 0),
                    particleDirection, Color.rgb(25, 255, 25));

            mBlueParticleShooter = new ParticleShooter(new Geometry.Point(1, 0, 0),
                    particleDirection, Color.rgb(5, 50, 255));
            final float angleVarianceInDegrees = 5f;
            final float speedVariance = 1f;

            mRedParticleShooter = new ParticleShooter(new Geometry.Point(-1, 0, 0),
                    particleDirection, Color.rgb(250, 50, 5), angleVarianceInDegrees, speedVariance);

            mGreenParticleShooter = new ParticleShooter(new Geometry.Point(0, 0, 0),
                    particleDirection, Color.rgb(25, 255, 25), angleVarianceInDegrees, speedVariance);

            mBlueParticleShooter = new ParticleShooter(new Geometry.Point(1, 0, 0),
                    particleDirection, Color.rgb(5, 50, 255), angleVarianceInDegrees, speedVariance);
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            // 设置视图尺寸
            GLES20.glViewport(0, 0, width, height);

            // 创建透视投影
            Matrix.perspectiveM(projectionMatrix, 0, 45, (float)width / (float)height, 1f, 10f);

            updateViewMatrices();
        }

        @Override
        public void onDrawFrame(GL10 gl) {
            // 清空屏幕
            GLES20.glClear(GL10.GL_COLOR_BUFFER_BIT);

            float currentTime = (System.nanoTime() - mGlobalStartTime) / 1000000000f;
            mRedParticleShooter.addParticles(mParticle, currentTime, 5);
            mGreenParticleShooter.addParticles(mParticle, currentTime, 5);
            mBlueParticleShooter.addParticles(mParticle, currentTime, 5);

            mParticleProgram.setUniform(viewProjectionMatrix);
            mParticleProgram.setCurrentTime(currentTime);
            mParticle.bindData(mParticleProgram);
            mParticle.draw();
        }

        private void handleOffsetsChanged(float xOffset, float yOffset) {
            this.xOffset = (xOffset - 0.5f) * 2.5f;
            this.yOffset = (yOffset - 0.5f) * 2.5f;
            updateViewMatrices();
        }

        private void updateViewMatrices() {
            // 定义模型矩阵
            Matrix.setIdentityM(viewMatrix, 0);
            Matrix.translateM(viewMatrix, 0, 0f - xOffset, -1.5f - yOffset, -5f);

            Matrix.multiplyMM(viewProjectionMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
        }

    }

}
显示如下


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值