第一篇:android实验报告
移动应用开发实验报告
实验名称
音乐播放器
班
级
学
号
姓
名
指导教师
实验成绩
2016 年04月
一、实验目的
本项目是一款基于Android手机平台的音乐播放器,使Android手机拥有个性的多媒体播放器,使手机显得更生动灵活化,与人们更为接近,让手机主人随时随地处于音乐视频的旋律之中。使人们的生活更加多样化。也使设计者更加熟练Android的技术和其它在市场上的特点。
二、实验内容及要求
在其中写清楚这个实验具体要你做什么,怎么做,要达到什么样的效果等。本设计实现的主要功能是播放Mp3,Wav多种格式的音乐文件,并且能够控制播放,暂停,停止,下一首,上一首播放列等基本播放控制功能,界面简明,操作简单。
三、实验方案设计
在其中写清楚你的程序的详细设计,用流程图配文字的形式描述。如果其中涉及到算法,一定要把算法阐述清楚。
3.1.1假设安装了音乐播放器的用户是系统的主要设计对象,其拥有以下操作,启动软件、播放音乐、暂停播放、停止播放、退出软件,其用例图如下
图2.1 播放器基本用例图
3.1.2用例分析 用例名称:启动软件 参与者:用户
目标:使得用户启动软件并加载手机和sd卡上的音频文件到播放列表 前置条件:无
基本事件流:1.用户启动软件
2.播放器将播放列表中的当前的歌曲
用例名称:播放 参与者:用户
目标:使得用户可以播放在播放列表中选中的歌曲 前置条件:播放器正在运行
基本事件流:1.用户单击“播放”按钮
2.播放器将播放列表中的当前的歌曲
用例名称:暂停 参与者:用户
目标:使得用户可以暂停正在播放的歌曲 前置条件:歌曲正在播放且未停止和暂停 基本事件流:1.用户单击“暂停”按钮
2.播放器将暂停当前的歌曲
④用例名称:停止 参与者:用户
目标:使得用户可以停止正在播放的歌曲 前置条件:歌曲正在播放或暂停 基本事件流:1.用户单击“停止”按钮
2.播放器将停止当前播放的歌曲
⑤用例名称:推出 参与者:用户
目标:使得用户退出或者后台播放音乐 前置条件:程序在运行
基本事件流:1.用户按返回键
2.播放器退出或者进入后台播放
四、实验测试
Step1.启动软件后,软件自动检索手机和sd卡的音频文件,并组织显示成列表.Step2.点击列表的歌曲名字。
Step3.播放音乐。
Step4.点击暂停,音乐暂停
Step5.点击播放 转到step3 Step6.点击停止 停止播放音乐
Step7.点击退出,若音乐处于播放状态,则音乐转向后台播放,界面退出。
Step8.点击退户,若音乐处于暂停或者停止状态,直接退出。
音乐播放器流程图
4.1MusicInfoController类
这个类继承于service,是播放音乐的服务类。播放音乐,暂停音乐,停止播放等操作都封装在这个类中。
主要的执行动作有:
4.1.1.类启动 onCreate(){
mMediaPlayer = new MediaPlayer();//分配一个播放对象
mMediaPlayer.setOnPreparedListener(mPrepareListener);//绑定之前
mMediaPlayer.setOnCompletionListener(mCompleteListener);//绑定之 后
}
4.1.2.服务绑定activity
MediaPlayer.OnCompletionListener mCompleteListener = new
MediaPlayer.OnCompletionListener()//实例化一个绑定监听器的匿名类
{
public void onCompletion(MediaPlayer mp)//完成绑定后
{
broadcastEvent(PLAY_COMPLETED);//广播消息
}
};
4.2MusicInfoController类
这个类主要用于获取android系统中的音频文件,并提供访问接口,它是一个单例类。
4.2.1获得播放文件列表
private Cursor query(Uri uri, String[] prjs, String selections, String[] selectArgs, String order){ ContentResolver resolver = pApp.getContentResolver();//取得一个连接对象if(resolver == null){
return null;
}
return resolver.query(uri, prjs, selections, selectArgs, order);} public Cursor getAllSongs(){
return query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);//查询ContentResolver 的所有音频文件
} 4.3MusicList类
改类继承于ListActivity,主要用于显示歌曲列表,并且封装部分操作,以及与父级目标通信。
4.3.1播放
protected void onListItemClick(ListView l, View v, int position, long id){ //歌曲列表的某项被点击
super.onListItemClick(l, v, position, id);
if(mCursor == null ||mCursor.getCount()== 0){
return;
}
mCursor.moveToPosition(position);//游标移动到当前路径
String url = mCursor.getString(mCursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));//取得绝对路径
mMusicPlayerService.setDataSource(url);//传递绝对路径
mMusicPlayerService.start();//播放音乐
}
4.3.2暂停/播放
mPlayPauseButton.setOnClickListener(new Button.OnClickListener(){
public void onClick(View v){
if(mMusicPlayerService!= null &&
mMusicPlayerService.isPlaying()){
mMusicPlayerService.pause();//音乐播放的服务暂停
mPlayPauseButton.setText(R.string.play);//改变按钮文字
} else if(mMusicPlayerService!= null){
mMusicPlayerService.start();//如果已经是暂停,则播放音乐
mPlayPauseButton.setText(R.string.pause);//改变文字
}
}
});
4.3.3停止
mStopButton.setOnClickListener(new Button.OnClickListener(){
public void onClick(View v){
// Perform action on click
if(mMusicPlayerService!= null){
mTextView.setVisibility(View.VISIBLE);//改变文字状态
mPlayPauseButton.setVisibility(View.INVISIBLE);//隐藏按钮
mStopButton.setVisibility(View.INVISIBLE);//隐藏停止按钮
mMusicPlayerService.stop();//后台音乐停止播放
}
}
});4.4MusicPlayerApp类
该类继承与Application,是程序的生存类。可以标识音乐播放器的生命周期,包括音乐在后台播放等。
4.4.1单例模式
public void onCreate(){
super.onCreate();
mMusicInfoController = MusicInfoController.getInstance(this);//返回该类的一个唯一实例
}
public MusicInfoController getMusicInfoController(){
return mMusicInfoController;}
五、程序的使用手册
系统编译生成apk文件,将apk文件拷到手机或者sd卡中,直接打开即可安装,或者安装360手机助手通过usb调试的方式进行安装。
启动软件后,加载歌曲列表现在这个界面上,如01表示歌曲名,unknown表示歌曲的演唱者
软件启动界面
从加载的歌曲列表中点击要播放的歌曲,开始播放
音乐播放界面
六、心得体会
通过对Android手机平台的音乐播放器软件的开发,使我对Android音乐播放器系统的整体设计有一个深入的了解,对整个流程也会有一个清晰的认识。开发Android音乐播放器,要抓住开发的核心部分,音乐播放器大体由播放主界面、播放列表、菜单、播放设置、文件浏览、歌曲搜索六大核心组成,只要掌握了这六部分的开发,音乐播放器就能初具规模。而其它的功能都是在这六个功能的基础上去补充添加的,但是这是功能的确是必不可少的功能,否则就不能算是音乐播放器了。
第二篇:Android实验报告—网络通信
实验三
Android网络通信
实验目的:
本实验的目的是使学生深入了解利用Intent实现进程间的通信过程。学会利用Intent进行Activity的跳转,以及链接网页信息;学会利用Intent将其他Activity的信息返回到Activity中的方法。体会Activity间通信的过程。
实验要求:
编程实现下述功能:主界面上有一个“登录”按钮和“链接网页”按钮,点击“登录”按钮后打开一个新的Activity;新的Activity上面有输入用户名和密码的控件(如下图所示)点击“链接网页”按钮,新的Activity上面有输入Uri信息的控件,可以链接到相应的网站,在用户关闭这个Activity后,返回到主界面中
程序界面如下图所示:
[实现提示]
1、建立Android工程,其中 工程名称:WebCommunication579
包名称:cn.edu.bistu.dj1001.WebCommunication579 Activity名称:WebCommunication579
2、工程建立完毕后,首先进行界面设计,建立相应的子Layout界面
3、在工程中添加相应的.java文件,处理各个Activity的事件响应
4、在Manifest中添加新建的Activity信息,进行注册。
程序源码:
主界面java文件代码: package cn.deu.bistu.dj1001.WebCommunication579;
import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;
public class WebCommunication579 extends Activity { private Button btnLogin,btnGoToWeb;private TextView show;private static final int SUBACTIVITY1 = 1;@Override
public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.main);btnLogin=(Button)findViewById(R.id.btnLogin);btnGoToWeb=(Button)findViewById(R.id.btnGoToWeb);show=(TextView)findViewById(R.id.A1show);
btnLogin.setOnClickListener(new OnClickListener(){ public void onClick(View v){ Intent intent = new Intent(WebCommunication592.this, activity1.class);
startActivityForResult(intent, SUBACTIVITY1);
}});btnGoToWeb.setOnClickListener(new OnClickListener(){ public void onClick(View v){ Intent intent = new Intent(WebCommunication592.this, activity2.class);startActivity(intent);}});} protected void onActivityResult(int requestCode, int resultCode, Intent data){ super.onActivityResult(requestCode, resultCode, data);switch(requestCode){ case SUBACTIVITY1: if(resultCode == RESULT_OK){Uri uriData = data.getData();show.setText(uriData.toString());} break;}};} 界面一java文件代码:
package cn.deu.bistu.dj1001.WebCommunication579;
import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;
public class activity1 extends Activity { private Button btnOK,btnCancel;private EditText edtInput;public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.activity1);edtInput=(EditText)findViewById(R.id.edtA1Input);btnOK=(Button)findViewById(R.id.btnA1OK);btnCancel=(Button)findViewById(R.id.btnA1Cancel);btnOK.setOnClickListener(new OnClickListener(){
public void onClick(View v){ String uriString = edtInput.getText().toString();Uri data = Uri.parse(uriString);Intent result = new Intent(null, data);setResult(RESULT_OK, result);finish();}});btnCancel.setOnClickListener(new OnClickListener(){ public void onClick(View view){ finish();}});}} 界面二java文件代码:
package cn.deu.bistu.dj1001.WebCommunication579;
import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;
import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;
public class activity2 extends Activity { private EditText edtInput;private Button btnOK,btnCancel;public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.activity2);edtInput=(EditText)findViewById(R.id.edtA2Input);btnOK=(Button)findViewById(R.id.btnA2OK);btnCancel=(Button)findViewById(R.id.btnA2Cancel);btnOK.setOnClickListener(new OnClickListener(){ public void onClick(View v){ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(edtInput.getText().toString()));startActivity(intent);}});btnCancel.setOnClickListener(new OnClickListener(){
public void onClick(View v){
finish();
}});}} 主界面的xml文件代码:
xmlns:android=“http://schemas.android.com/apk/res/android” android:orientation=“Horizontal” android:layout_width=“fill_parent” android:layout_height=“fill_parent”> android:text=“" android:id=”@+id/A1show“ android:layout_width=”wrap_content“ android:layout_height=”wrap_content“>
界面一的xml文件代码:
android:orientation=”Horizontal“ android:layout_width=”fill_parent“ android:layout_height=”fill_parent“ xmlns:android=”http://schemas.android.com/apk/res/android“> android:layout_width=”wrap_content“ android:layout_height=”wrap_content“> android:text=”用户名和密码:“ android:layout_width=”wrap_content“ android:layout_height=”wrap_content“> android:text=”“ android:id=”@+id/edtA1Input“ android:layout_width=”wrap_content“ android:layout_height=”wrap_content“> android:layout_width=”wrap_content“ android:layout_height=”wrap_content“>
界面二的xml文件代码: xmlns:android=”http://schemas.android.com/apk/res/android“> android:text=”“ android:id=”@+id/edtA2Input“ android:layout_width=”match_parent“ android:layout_height=”wrap_content“>
程序运行结果:
程序包:
主界面:
点击登录按钮后:
点击确定按钮后:
点击链接网页按钮后:
点击确定按钮后:
实验心得体会:
通过本次实验深入了解了Intent实现进程间的通信过程。熟悉了利用Intent将其他Activity的信息返回到Activity中的方法,可以更熟练的使用安卓编程软件。
第三篇:Android实验报告—UI设计(定稿)
Android UI设计
实验目的:
本实验的目的是使学生深入了解Android程序框架结构、了解和掌握Android界面设计和界面编程。通过程序设计,掌握常用界面控件、菜单、以及界面事件的响应。
实验要求:
设计程序实现一个电子菜单,应具有显示菜单功能和选菜功能。通过选择,将选中的菜单选项在界面做显示,如下图:
[实现提示]
1、建立Android工程,其中 工程名称:MenuSelect579 应用名称:MenuSelect579 包名称:cn.edu.bistu.dj1001.MenuSelect579 Activity名称:MenuSelect579
2、工程建立完毕后,进行相应界面设计,再编写Java文件
程序源码
package cn.edu.bistu.dj1001.MenuSelect579;import android.app.Activity;
import android.os.Bundle;import android.view.ContextMenu;import android.view.ContextMenu.ContextMenuInfo;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.TextView;public class MenuSelect579 extends Activity {
/** Called when the activity is first created.*/
TextView LabelView = null;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LabelView =(TextView)findViewById(R.id.label);registerForContextMenu(LabelView);
}
final static int CONTEXT_MENU_1 = Menu.FIRST;
final static int CONTEXT_MENU_2 = Menu.FIRST+1;
final static int CONTEXT_MENU_3 = Menu.FIRST+2;
@Override
public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo){
menu.setHeaderTitle(“今日菜单”);
menu.add(0, CONTEXT_MENU_1, 0,“宫保鸡丁”);
menu.add(0, CONTEXT_MENU_2, 1,“干煸豆角”);
menu.add(0, CONTEXT_MENU_3, 2,“鱼香肉丝”);
}
@Override
}
public boolean onContextItemSelected(MenuItem item){
} switch(item.getItemId()){
case CONTEXT_MENU_1: LabelView.setText(“宫保鸡丁”);return true;case CONTEXT_MENU_2: LabelView.setText(“干煸豆角”);return true;case CONTEXT_MENU_3: LabelView.setText(“鱼香肉丝”);return true;} return false;
程序运行结果:
实验心得体会:(可选)
通过本次实验熟悉了android的界面设计简单方法和界面编程,锻炼了实际动手能力,熟悉了 Android程序框架结构、Android界面设通过程序设计,掌握了常用界面控件、菜单、以及界面事件的响应。
第四篇:Android实验格式简易计算器实验报告
实验报告
2013-2014 学年第2学期
课程名称:嵌入式操作系统
实验题目:简易计算器的设计与实现
专业:计算机科学与技术、信息处理(是什么专业,写什么专业)班级:计算本1101(按自己班级填写)
日期填写 2014年4月 8日
实验题目:简易计算器的设计与实现
实验类型:上机实验
一、实验目的及要求
1.掌握线性布局的应用;
2.掌握表格布局的应用;
3.掌握数组的应用;
4.掌握如何Button组件的使用;
5.掌握代码中访问布局组件的方法;
6.掌握特定组件的事件设计方法。
二、实验仪器设备与软件环境
1、电脑。
2、Android集成开发工具adt-bundle。
三、实验过程
1、布局设计
…这部分自己填
2.程序设计
…这部分自己填
第五篇:Android 3D相册实验报告
中原工学院计算机学院 软件平台开发技术
大作业
专 业: 软件工程 班 级: 软件121 作品名称: 3D相册 姓 名: 辛俊闪 学 号: 201200834101 指导教师: 刘凤华
2015年 6 月 15 日
一、设计目的
奔着让二维的手机照片能够显示出3D的立体效果,让我们的相册更加炫的目的,我初步的想法是开发一个基于android平台的手机相册小应用。
二、作品简介
该应用是基于android开发,将相册置于立体空间中呈现,并且可以通过用手指横向滑动手机屏幕的方式来选择所有浏览的图片,在滑动过程中相册的旋转同时带有惯性因素,使场景效果更自然、更人性化,手指点击一张照片可以进入单独显示对应照片界面,在该界面操作左滑右滑可以切换照片下一张上一张。在浏览完成后,可以按返回键跳转回相册显示。
三、设计思路
3.1 用到的主要技术
本项目开发过程中,用到了OpenGL ES中的图形绘制技术,包括纹理映射技术、物体旋转技术glRotatef()、物体的平移技术glTranslatef(),并且应用到了屏幕触控技术。
3.2 相关技术难点学习
(1)android开发中关于GLSurfaceView简介
SDK 中的 android.opengl.GLSurfaceView 类提供如下功能: 在 OpenGL ES 和 View 系统之间建立联系;
使得 OpenGL ES 可以工作在 Activity 生命周期中; 可选择合适的 frame buffer 像素格式;
创建并管理一个单独的渲染线程,可以实现平滑的动画; 提供 debugging 工具和 API。
GLSurfaceView.Render 接口有三个方法:
onSurfaceCreated():该方法在渲染开始前调用,OpenGL ES 的绘制上下文被重建时也会被调用。当 activity 暂停时绘制上下文会丢失,当 activity 继续时,绘制上下文会被重建。另外,创建长期存在的 OpenGL 资源(如 texture)往往也在这里进行。
onSurfaceChanged():当 surface 的尺寸发生改变时该方法被调用。往往在这里设置 viewport。若你的 camera 是固定的,也可以在这里设置 camera。
onDrawFrame():每帧都通过该方法进行绘制。绘制时通常先调用 glClear 函数来清空 framebuffer,然后在调用 OpenGL ES 的起它的接口进行绘制。
(2)初始化GLSurfaceView
初始化过程其实仅需要你使用setRenderer(Renderer)设置一个渲染(render)。当然,你也可以修改GLSurfaceView一些默认配置。
* setDebugFlags(int)* setEGLConfigChooser(boolean)* setEGLConfigChooser(EGLConfigChooser)* setEGLConfigChooser(int, int, int, int, int, int)* setGLWrapper(GLWrapper)
(3)定制android.view.Surface
GLSurfaceView默认会创建像素格式为PixelFormat.RGB_565的surface。如果需要透明效果,调用 getHolder().setFormat(PixelFormat.TRANSLUCENT)。透明(TRANSLUCENT)的surface的像 素格式都是32位,每个色彩单元都是8位深度,像素格式是设备相关的,这意味着它可能是ARGB、RGBA或其它。
(4)选择EGL配置
Android设备往往支持多种EGL配置,可以使用不同数目的通道(channel),也可以指定每个通道具有不同数目的位(bits)深度。因此,在渲染器工作之前就应该指定EGL的配置。GLSurfaceView默认EGL配置的像素格式为RGB_656,16位的深度缓存(depth buffer),默认不开启遮罩缓存(stencil buffer)。如果你要选择不同的EGL配置,请使用setEGLConfigChooser方法中的一种。
(5)调试行为
你可以调用调试方法setDebugFlags(int)或setGLWrapper(GLSurfaceView.GLWrapper)来自定义 GLSurfaceView一些行为。在setRenderer方法之前或之后都可以调用调试方法,不过最好是在之前调用,这样它们能立即生效。
(6)设置渲染器
总之,你必须调用setRenderer(GLSurfaceView.Renderer)来注册一个GLSurfaceView.Renderer渲染器。渲染器负责真正的GL渲染工作。
(7)渲染模式
渲染器设定之后,你可以使用setRenderMode(int)指定渲染模式是按需(on demand)还是连续(continuous)。默认是连续渲染。
(8)Activity生命周期
Activity窗口暂停(pause)或恢复(resume)时,GLSurfaceView都会收到通知,此时它的onPause方法和 onResume方法应该被调用。这样做是为了让GLSurfaceView暂停或恢复它的渲染线程,以便它及时释放或重建OpenGL的资源。
(9)事件处理
为了处理事件,一般都是继承GLSurfaceView类并重载它的事件方法。但是由于GLSurfaceView是多线程操作,所以需要一些特殊的处 理。由于渲染器在独立的渲染线程里,你应该使用Java的跨线程机制跟渲染器通讯。queueEvent(Runnable)方法就是一种相对简单的操 作
四、主要实现
4.1Activity类的开发过程
(1)重写onCreate()方法
//设置全屏显示
requestWindowFeature(Window.FEATURE_NO_TITLE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//横屏显示设置
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//设置屏幕分辨率
DisplayMetrics dm=new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);mGLSurfaceView=new MySurfaceView(this);mGLSurfaceView.screenHeight=dm.heightPixels;mGLSurfaceView.screenWidth=dm.widthPixels;//获取屏幕焦点并使其可触控显示
mGLSurfaceView.ratio=mGLSurfaceView.screenWidth/mGLSurfaceView.screenHeight;mGLSurfaceView.requestFocus();mGLSurfaceView.setFocusableInTouchMode(true);(2)重写onResume()方法
//Activity恢复(resume)时,GLSurfaceView都会收到通知,此时它的onResume方法应该被调用。这样做是为了让GLSurfaceView恢复它的渲染线程,以便它及时重建OpenGL的资源。
Constant.threadWork=false;mGLSurfaceView.onPause();
(3)重写onPause()方法
//Activity窗口暂停(pause)时,GLSurfaceView都会收到通知,此时它的onPause方法应该被调用。这样做是为了让GLSurfaceView暂停它的渲染线程,以便它及时释放OpenGL的资源。
Constant.threadWork=true;
mGLSurfaceView.onResume();4.2界面实现类的开发过程
(1)界面类的构造器部分
public MySurfaceView(Context context){ super(context);mRenderer = new SceneRenderer();//创建场景渲染器
setRenderer(mRenderer);
//设置渲染器
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//设置渲染模式为主动渲染连续渲染
//启动一个线程根据当前的角速度旋转场景
threadWork=true;new Thread(){ public void run(){
while(threadWork)
{
.....} } }.start();}(2)按键单击事件
public boolean onKeyDown(int keyCode, KeyEvent e){ if(keyCode==4)
} {//若按下的是返回键
if(isCheck)
{//若在detail场景中则回主场景
isCheck=false;} else
{//若在主场景中则退出程序
System.exit(0);} } return true;(3)屏幕触控事件回调方法
public boolean onTouchEvent(MotionEvent e){
if(isCheck){//若在detail中
float bx = e.getX();//获取触控点X坐标
dbx = bxmPreviousX;//计算X向触控位移
float dy = y-mPreviousY;//计算Y向触控位移
long currTime=System.currentTimeMillis();//获取当前时间戳 单位为毫秒
long timeSpan=(currTime-previousTime)/10;//计算两次触控事件之间的时间差
switch(e.getAction()){ case MotionEvent.ACTION_DOWN: isMove=false;break;case MotionEvent.ACTION_MOVE:
if(Math.abs(dx)>5||Math.abs(dy)>5){//触控位移大于阈值则进入移动状态
isMove=true;} if(isMove){//若在移动状态则计算角度变化速度
if(timeSpan!=0){
yAngleV=dx * TOUCH_SCALE_FACTOR/timeSpan;} } break;case MotionEvent.ACTION_UP:
//若在非移动状态且角度速度为0则看选中的是哪幅照片来显示 if(!isMove&&yAngleV==0){ //折算出触控点在NEAR面上的位置
float nearX=(x-screenWidth/2)*ratio/(screenWidth/2);float nearY=(screenHeight/2-y)/(screenHeight/2);
//先判断点下去的是左边还是右边 if(x>screenWidth/2)
{//右边
ArrayList
for(int i=0;i
{
//计算此幅照片的角度
float tempAngle=(i*PHOTO_ANGLE_SPAN+yAngle)%360;
//若角度在270到360范围内则在右边的前面
if(tempAngle>270&&tempAngle<360)
{
al.add(new
CandidataDis(tempAngle-270,tempAngle,i));
}
} //根据与270度的夹角排序,夹角小的排在前面 Collections.sort(al);
//遍历候选列表谁在X范围内谁单独显示
currIndex=-1;
for(CandidataDis cd:al)
{
if(cd.isInXRange(nearX,nearY))
{
currIndex=cd.index;
break;
}
}
}
else
{
ArrayList
for(int i=0;i
{
//计算此幅照片的角度
float tempAngle=(i*PHOTO_ANGLE_SPAN+yAngle)%360;//若角度在180到270范围内则在左边的前面 if(tempAngle>180&&tempAngle<270){
al.add(new CandidataDis(270-tempAngle,tempAngle,i));
}
}
//根据与270度的夹角排序,夹角小的排在前面 Collections.sort(al);//遍历候选列表谁在X范围内谁单独显示
currIndex=-1;for(CandidataDis cd:al){ if(cd.isInXRange(nearX,nearY)){
currIndex=cd.index;
break;} } }
//若有选中照片,则设置进入detail显示状态
if(currIndex!=-1)
{
isCheck=true;
}
} isMove=false;break;} mPreviousX = x;//记录触控笔位置
mPreviousY = y;//记录触控笔位置
previousTime=currTime;//记录此次时间
return true;}(4)渲染器内部类开发
private class SceneRenderer implements GLSurfaceView.Renderer { Board tp=new Board();//用于显示照片的纹理矩形
@Override
public void onDrawFrame(GL10 gl){.....} }(5)初始化纹理
public int initTexture(GL10 gl,int drawableId)//textureId
{
....}
五、作品展示
(1)应用主界面
通过滑动手机屏幕的方式改变照片的呈现角度。
(2)detail界面
通过单击主界面的照片进入detail界面,左右滑动查看上一张下一张。
六、心得体会
一直都很喜欢3D做成的软件,但是对于android的3D开发却从来没有接触过,本来是想着做一个3D游戏的,但是在学习的过程中发现对于一个初学者来说想在短时间内做好一个3D游戏开发是非常困难,于是就选择了一个相对简单的3D相册练练手。
在做这个小应用的过程中也遇到了很多问题,比如说GLSurfaceView的应用问题,渲染器的使用问题,缓冲区的分配回收问题等等,曾经也为了这些新知识头痛了很久,查找了很多网上的资料也专门从图书馆借了几本关于3D开发的书,最后总算是把问题都解决了,虽然不能说完全理解,但是能够灵活运用。