精华内容
下载资源
问答
  • Android SurfaceView实现画心

    千次阅读 2016-12-27 20:33:04
    谁说程序员不会浪漫,浪漫是跟...SurfaceView的用法有基础的应该知道,这里不多做介绍,大体流程:继承SurfaceView实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->Surfac

    谁说程序员不会浪漫,浪漫是跟人有关的,程序员也是可以很浪漫的,今天就用Android 的SurfaceView 实现画心功能。

    SurfaceView的用法有基础的应该知道,这里不多做介绍,大体流程:继承SurfaceView并实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->SurfaceHolder.addCallback(callback)添加回调函数---->SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布----> Canvas绘画 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。

    根据心形公式:(参考http://blog.csdn.net/decting/article/details/8580634)


    公式中t的取值是0~360,这样的话开始画的位置是从下图2的位置开始,这里我让t的取值+180,目的是让开始画的位置从下面左边开始,如图从1处开始


    公式中t的取值是0~360,但是编程中的三角函数都是用的弧度,所以要把t转成弧度

    t = i * 2 * Math.PI / 360d;

    核心代码如下:

    Paint paint = new Paint();// 创建画笔
                    paint.setStyle(Paint.Style.STROKE);
                    paint.setStrokeWidth(8);
                    paint.setColor(Color.GREEN);
                    Canvas canvas = null;
                    Path path = new Path();
                    for (int i = 0 + 180; i < 361 + 180; i++) {
                        try {
                            Thread.sleep(10);// 睡眠时间为10毫秒
                            synchronized (mHolder) {
                                canvas = mHolder.lockCanvas();// 锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
    
                                double st = i * 2 * Math.PI / 360d;
    
                                double x = 10 * 16 * Math.pow(Math.sin(sit), 3);
                                double y = 10 * (13 * Math.cos(sit) - 5 * Math.cos(2 * sit) - 2 * Math.cos(3 * sit) - Math.cos(4 * sit));
                                if (i == 180) {
                                    path.moveTo(mWidth / 2 + (float) (x), mHeight / 2 - (float) (y));
                                }
                                path.lineTo(mWidth / 2 + (float) (x), mHeight / 2 - (float) (y));
    
                                if (canvas != null)
                                    canvas.drawPath(path, paint);
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                if (canvas != null) {
                                    mHolder.unlockCanvasAndPost(canvas);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }

    效果图:


    源码:http://download.csdn.net/detail/bigboysunshine/9722879

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    展开全文
  • SurfaceView实现简单的相机 SurfaceView继承自View,主要用来展示视频流的绘制,典型的应用场景是相机,视频播放器,游戏界面绘制等。它独立于UI线程进行绘制,所以不会阻塞UI线程。本文将结合一个简单的相机demo...

    SurfaceView实现简单的相机

    视频流

    SurfaceView继承自View,主要用来展示视频流的绘制,典型的应用场景是相机,视频播放器,游戏界面绘制等。它独立于UI线程进行绘制,所以不会阻塞UI线程。本文将结合一个简单的相机demo介绍SurfaceView的使用。

    Github Demo地址

    我们实现的相机功能很简单,可以进行相机预览,点击拍照按钮拍照,并展示拍摄的照片,点击确定返回相机预览界面。

    布局如下:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        ...
    >
    
      <SurfaceView        
            android:id="@+id/preview_surface_view"                
            android:layout_width="match_parent"        
            android:layout_height="match_parent"/>    
    
      <ImageView        
            android:id="@+id/image_view"        
            android:layout_width="match_parent"        
            android:layout_height="match_parent"        
            android:visibility="gone"/>    
    
      <Button        
            android:id="@+id/take_photo_btn"        
            android:layout_width="wrap_content"        
            android:layout_height="wrap_content"        
            android:layout_alignParentBottom="true"        
            android:layout_centerHorizontal="true"        
            android:text="拍照"/>    
    
      <Button        
            android:id="@+id/confirm_btn"        
            android:layout_width="wrap_content"        
            android:layout_height="wrap_content"        
            android:layout_alignParentBottom="true"        
            android:layout_centerHorizontal="true"        
            android:text="确定"/>
    
    </RelativeLayout>
    

    SurfaceView的初始化如下,首先根据SurfaceView获取SurfaceHolder,SurfaceHolder是一个接口,提供了控制SurfaceView界面的函数,比如控制界面的尺寸、格式,编辑界面像素,监控界面的变化等。然后给SurfaceHolder添加CallBack回调函数,三个回调函数对应了界面的三个状态,创建,修改和销毁。在这里我们在界面创界后开始进行相机预览。

    public class MainActivity extends AppCompatActivity {
        ...
        private Camera camera;
        private SurfaceHolder surfaceHolder;
        private byte[] pictureDataBytes;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {    
            super.onCreate(savedInstanceState);
            ...
            surfaceHolder = surfaceView.getHolder();    
            surfaceHolder.addCallback(new SurfaceHolder.Callback() {        
                @Override        
                public void surfaceCreated(SurfaceHolder holder) {            
                    startPreview();        
                }        
    
                @Override        
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {        
    
                }        
    
                @Override        
                public void surfaceDestroyed(SurfaceHolder holder) {        
                
                }    
            });
    }
    

    相机的初始化在onResume里进行,销毁在onPause里进行:

    @Override
    protected void onResume() {    
        super.onResume();  
        initCamera();
    }
    
    @Override
    protected void onPause() {    
        super.onPause();    
        releaseCamera();
    }
    
    private void initCamera() {    
        if (camera == null) {        
            camera = Camera.open();    
        }
    }
    
    private void releaseCamera() {    
        if (camera != null) {        
            camera.release();        
            camera = null;    
        }
    }
    

    启动相机预览的函数实现如下,通过setPreviewDisplay指定显示预览的view:

    private void startPreview() {    
        if (camera != null) {        
            try {            
                camera.setPreviewDisplay(surfaceHolder);            
                if (isCapturing) {                
                    camera.startPreview();            
                }        
            } catch (IOException e) {            
                e.printStackTrace();            
                Toast.makeText(this, "Unable to open camera.", Toast.LENGTH_SHORT)                    .show();        
            }    
        }
    }
    

    点击拍照按钮,进行拍照并展示。这里为了防止相机拍摄的照片太大导致OOM错误,要对图片进行压缩,压缩包括两个方式,尺寸压缩和像素格式压缩,可以参考博客从Oppo手机拍照无法展示谈图片压缩

    @OnClick(R.id.take_photo_btn)
    protected void onTakePhotoClicked(View v) {    
        camera.takePicture(null, null, new Camera.PictureCallback() {        
            @Override        
            public void onPictureTaken(byte[] data, Camera camera) {            
                pictureDataBytes = data;            
                showPicture();        
            }    
        });
    }
    
    private void showPicture() {    
        Bitmap bitmap = BitmapFactory.decodeByteArray(pictureDataBytes, 0, pictureDataBytes.length);    
    
        BitmapFactory.Options options = new BitmapFactory.Options();    
        options.inSampleSize = calculateSampleSize(bitmap.getHeight(), bitmap.getWidth());    
        options.inPreferredConfig = Bitmap.Config.RGB_565;
    
        InputStream inputStream = bitmapToStream(bitmap);    
        imageView.setImageBitmap(BitmapFactory.decodeStream(inputStream, null, options));
        ...
    }
    

    计算采样比例采用下面的函数:

    // 获取采样比例
    public int calculateSampleSize(int outWidth, int outHeight) {    
        int scale = 1;    
        if (outHeight > MAX_HEIGHT || outWidth > MAX_WIDTH) {        
            int maxSize = MAX_WIDTH > MAX_HEIGHT ? MAX_WIDTH : MAX_HEIGHT;        
            scale = (int) Math.pow(2, (int) Math.round(Math.log(maxSize /(double) Math.max(outHeight, outWidth)) / Math.log(0.5)));    
        }    
    
        return scale;
    }
    

    最后记得在Manifest里添加相机权限:

    <uses-permission android:name="android.permission.CAMERA"/>
    

    Github Demo地址

    参考:
    https://developer.android.com/reference/android/view/SurfaceView.html
    http://archive.oreilly.com/oreillyschool/courses/android2/CameraAdvanced.html

    展开全文
  • 使用SurFaceView实现视频播放

    万次阅读 2016-04-21 20:26:14
    前言:虽然ViedoView控件可以播放视频,但播放的位置和大小并不受我们的控制,为了对...实现效果: 1、SurfaceView与MediaPlayer配合使用: mediaPlayer.setDisplay(surfaceview.getHolder());//这一步是关键,

    前言:虽然ViedoView控件可以播放视频,但播放的位置和大小并不受我们的控制,为了对视频有更好的控制权,可以使用MediaPlayer配合SurfaceView来播放视频。

    实现效果:



    1、SurfaceView与MediaPlayer配合使用:

    mediaPlayer.setDisplay(surfaceview.getHolder());//这一步是关键,制定用于显示视频的SurfaceView对象(通过setDisplay())

    2、维护SurfaceView:

    通过sufaceView.Callback接口实现,需要实现其三个方法:

    • void surfaceDestroyed(SurfaceHolder holder):当SurfaceHolder被销毁的时候回调。
    • void surfaceCreated(SurfaceHolder holder):当SurfaceHolder被创建的时候回调。
    • void surfaceChange(SurfaceHolder holder):当SurfaceHolder的尺寸发生变化的时候被回调。

    3、通过MediaPlayer类的Play()与Pause()方法实现视频的暂停与播放。

    4、对进度条的布局优化:

    在drawable下定义两个xml文件,具体见以下源码。


    完整源码展示:

    MainActivity.java:

    import android.app.Activity;
    import android.content.res.AssetFileDescriptor;
    import android.media.AudioManager;
    import android.media.MediaPlayer;
    import android.media.MediaPlayer.OnPreparedListener;
    import android.os.Bundle;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.ImageButton;
    import android.widget.SeekBar;
    
    public class MainActivity extends Activity implements OnClickListener {
    
    	private SurfaceView surfaceview;
    	private MediaPlayer mediaPlayer;
    	private ImageButton start;
    	private ImageButton share;
    	private ImageButton back;
    	private ImageButton pause;
    	private SeekBar seekBar;
    	private boolean isPlaying;
    	private int currentPosition = 0;
    
    	private int postion = 0;
    
    
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		findViewById();
    		initView();
    	}
    
    	protected void findViewById() {
    		// TODO Auto-generated method stub
    		surfaceview = (SurfaceView) findViewById(R.id.surfaceView);
    		start = (ImageButton) findViewById(R.id.video_start);
    		back = (ImageButton) findViewById(R.id.video_back);
    		pause = (ImageButton) findViewById(R.id.video_pause);
    		share = (ImageButton) findViewById(R.id.video_share);
    		seekBar = (SeekBar) findViewById(R.id.seekBar);
    
    
    
    	}
    
    	protected void initView() {
    		// TODO Auto-generated method stub
    		mediaPlayer = new MediaPlayer();
    		surfaceview.getHolder().setKeepScreenOn(true);
    		surfaceview.getHolder().addCallback(new SurfaceViewLis());
    		start.setOnClickListener(this);
    		back.setOnClickListener(this);
    		pause.setOnClickListener(this);
    		share.setOnClickListener(this);
    		seekBar.setOnClickListener(this);
    	}
    
    	private class SurfaceViewLis implements SurfaceHolder.Callback {
    
    		@Override
    		public void surfaceChanged(SurfaceHolder holder, int format, int width,
    				int height) {
    
    		}
    
    		@Override
    		public void surfaceCreated(SurfaceHolder holder) {
    			if (currentPosition > 0) {
    				// 创建SurfaceHolder的时候,如果存在上次播放的位置,则按照上次播放位置进行播放
    				video_play(currentPosition);
    				currentPosition = 0;
    			}
    		}
    
    		@Override
    		public void surfaceDestroyed(SurfaceHolder holder) {
    			// 销毁SurfaceHolder的时候记录当前的播放位置并停止播放
    			if (mediaPlayer != null && mediaPlayer.isPlaying()) {
    				currentPosition = mediaPlayer.getCurrentPosition();
    				mediaPlayer.stop();
    			}
    
    		}
    
    	}
    
    	@Override
    	public void onClick(View v) {
    		switch (v.getId()) {
    			case R.id.video_start:
    				video_play(0);
    				break;
    			case R.id.video_pause:
    				pause();
    				break;
    
    
    			default:
    				break;
    		}
    	}
    
    
    	/**
    	 * 开始播放
    	 *
    	 * @param msec 播放初始位置
    	 */
    	protected void video_play(final int msec) {
    //		// 获取视频文件地址
    		try {
    			mediaPlayer = new MediaPlayer();
    			//设置音频流类型
    			mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    			// 设置播放的视频源
    			AssetFileDescriptor fd = this.getAssets().openFd("Perspective.mp4");
    			mediaPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(),
    					fd.getLength());
    			// 设置显示视频的SurfaceHolder
    			mediaPlayer.setDisplay(surfaceview.getHolder());//这一步是关键,制定用于显示视频的SurfaceView对象(通过setDisplay())
    
    			mediaPlayer.prepareAsync();
    			mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
    
    				@Override
    				public void onPrepared(MediaPlayer mp) {
    					mediaPlayer.start();
    
    					// 按照初始位置播放
    					mediaPlayer.seekTo(msec);
    					// 设置进度条的最大进度为视频流的最大播放时长
    					seekBar.setMax(mediaPlayer.getDuration());
    					// 开始线程,更新进度条的刻度
    					new Thread() {
    
    						@Override
    						public void run() {
    							try {
    								isPlaying = true;
    								while (isPlaying) {
    									int current = mediaPlayer
    											.getCurrentPosition();
    									seekBar.setProgress(current);
    
    									sleep(500);
    								}
    							} catch (Exception e) {
    								e.printStackTrace();
    							}
    						}
    					}.start();
    
    					start.setEnabled(false);
    				}
    			});
    			mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    
    				@Override
    				public void onCompletion(MediaPlayer mp) {
    					// 在播放完毕被回调
    					start.setEnabled(true);
    				}
    			});
    
    			mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    
    				@Override
    				public boolean onError(MediaPlayer mp, int what, int extra) {
    					// 发生错误重新播放
    					video_play(0);
    					isPlaying = false;
    					return false;
    				}
    			});
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    
    	}
    
    
    	/**
    	 * 暂停或继续
    	 */
    	protected void pause() {
    		if (mediaPlayer != null && mediaPlayer.isPlaying()) {
    			mediaPlayer.pause();
    		}
    
    	}
    
    
    
    
    }
    

    activity_main.xml:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="220dp">
    
            <SurfaceView
                android:id="@+id/surfaceView"
                android:layout_width="match_parent"
                android:layout_height="220dp"/>
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="30dp"
                android:layout_gravity="top"
                android:orientation="horizontal"
                android:background="@drawable/video_top">
    
                <!--android:alpha="0.3"-->
    
                <ImageButton
                    android:id="@+id/video_back"
                    android:layout_width="15dp"
                    android:layout_height="18dp"
                    android:background="@drawable/video_back"
                    android:layout_gravity="center"
                    android:layout_marginLeft="20dp"></ImageButton>
    
                <ImageButton
                    android:id="@+id/video_share"
                    android:layout_width="25dp"
                    android:layout_height="15dp"
                    android:background="@drawable/video_share"
                    android:layout_gravity="center"
                    android:layout_marginLeft="280dp"
    
                    />
    
            </LinearLayout>
    
    
    
    
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="30dp"
                android:layout_gravity="bottom"
                android:orientation="horizontal"
                android:background="@drawable/video_bottom">
    
            <ImageButton
                android:id="@+id/video_start"
                android:layout_width="18dp"
                android:layout_height="wrap_content"
                android:background="@drawable/video_start"
                android:layout_gravity="center"
                android:layout_marginLeft="20dp">
    
            </ImageButton>
    
    
    
    
    
    
                <SeekBar
                    android:id="@+id/seekBar"
                    android:layout_width="250dp"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_marginLeft="20dp"
                    android:progressDrawable="@drawable/seekbar_style"
                    android:thumb="@drawable/seekbar_thumb"
                    android:maxHeight="8dp"
                    android:minHeight="8dp"
    
                    />
    
            <ImageButton
                android:id="@+id/video_pause"
                android:layout_width="15dp"
                android:layout_height="18dp"
                android:background="@drawable/video_pause"
                android:layout_gravity="center"
                android:layout_marginLeft="20dp"
                />
    
    
        </LinearLayout>
    
    
        </FrameLayout>
    
    
    </RelativeLayout>


    对进度条的布局优化:

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list
        xmlns:android="http://schemas.android.com/apk/res/android">
        <item >
            <shape>
                <solid android:color="#c6c6c6" />
            </shape>
        </item>
        <item>
            <clip>
                <shape>
                    <solid android:color="#06a7fa" />
                </shape>
            </clip>
        </item>
    </layer-list>

    对进度点的布局优化:

    <?xml version="1.0" encoding="UTF-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- 按下状态 -->
        <item
            android:state_pressed="true"
            android:drawable="@drawable/video_seekbar_after" />
    
        <!-- 普通无焦点状态 -->
        <item
            android:state_focused="false"
            android:state_pressed="false"
            android:drawable="@drawable/video_seekbar_before" />
    
    </selector> 


    --end--

     ps:后期会对视频进行更多优化处理。




    展开全文
  • 因为这个类实现了SurfaceHolder.Callback接口,所以回调参数直接this surfaceHolder.setFixedSize(320, 220);  // 显示的分辨率,不设置为视频默认 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_...

    1.案例一

    布局文件:

    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent" android:weightSum="1">
        <SurfaceView android:layout_height="220dip" android:layout_gravity="center" android:id="@+id/surface" android:layout_weight="0.25" android:layout_width="320dip"></SurfaceView>
        <LinearLayout android:id="@+id/linearLayout1" android:layout_height="wrap_content" android:layout_width="fill_parent">
            <Button android:text="播放" android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
            <Button android:text="暂停" android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
            <Button android:text="停止" android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
        </LinearLayout>
    </LinearLayout>
    复制代码

    主程序:

    复制代码
    public class SurfaceActivity extends Activity implements SurfaceHolder.Callback {
        /** Called when the activity is first created. */
        MediaPlayer player;
        SurfaceView surface;
        SurfaceHolder surfaceHolder;
        Button play,pause,stop;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            play=(Button)findViewById(R.id.button1);
            pause=(Button)findViewById(R.id.button2);
            stop=(Button)findViewById(R.id.button3);
            surface=(SurfaceView)findViewById(R.id.surface);
     
            surfaceHolder=surface.getHolder();  //SurfaceHolder是SurfaceView的控制接口
            surfaceHolder.addCallback(this);   //因为这个类实现了SurfaceHolder.Callback接口,所以回调参数直接this
            surfaceHolder.setFixedSize(320, 220);  //显示的分辨率,不设置为视频默认
            surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  //Surface类型
     
            play.setOnClickListener(new OnClickListener(){
                 @Override
                public void onClick(View v) {
                    player.start();
                }});
            pause.setOnClickListener(new OnClickListener(){
                @Override
                public void onClick(View v) {
                    player.pause();
                }});
            stop.setOnClickListener(new OnClickListener(){
                 @Override
                public void onClick(View v) {
                    player.stop();
                }});
        }
     
        @Override
        public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        }
     
        @Override
        public void surfaceCreated(SurfaceHolder arg0) {
    //必须在surface创建后才能初始化MediaPlayer,否则不会显示图像
            player=new MediaPlayer();
            player.setAudioStreamType(AudioManager.STREAM_MUSIC);
            player.setDisplay(surfaceHolder);
            //设置显示视频显示在SurfaceView上
                try {
                    player.setDataSource("/sdcard/3.mp4");
                    player.prepare();
                } catch (Exception e) {
                    e.printStackTrace();
                }
        }
     
        @Override
        public void surfaceDestroyed(SurfaceHolder arg0) {
            // TODO Auto-generated method stub
     
        }
     
        @Override
        protected void onDestroy() {
            // TODO Auto-generated method stub
            super.onDestroy();
            if(player.isPlaying()){
            player.stop();
            }
            player.release();
            //Activity销毁时停止播放,释放资源。不做这个操作,即使退出还是能听到视频播放的声音
        }
    }
    复制代码

    2.案例二

    布局文件main.xml

    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#ffffff"
        >
    <TextView  
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="@string/filename"
        />
    <EditText android:layout_width="fill_parent" 
        android:layout_height="wrap_content"  
        android:text="oppo.mp4"
        android:id="@+id/filename"
        />
    <LinearLayout 
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
        <ImageButton  android:layout_width="wrap_content"
        android:layout_height="fill_parent"
            android:src="@drawable/play"
            android:id="@+id/play"
        />
        <ImageButton  android:layout_width="wrap_content"
        android:layout_height="fill_parent"
            android:src="@drawable/pause"
            android:id="@+id/pause"
        />
        <ImageButton  android:layout_width="wrap_content"
        android:layout_height="fill_parent"
            android:src="@drawable/stop"
            android:id="@+id/stop"
        />
        <ImageButton  android:layout_width="wrap_content"
        android:layout_height="fill_parent"
            android:src="@drawable/reset"
            android:id="@+id/reset"
        />
    </LinearLayout>
     <SurfaceView android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/surfaceview"
        />
    </LinearLayout>
    复制代码

    主程序VodeoPlayActivity.java

    复制代码
    public class VodeoPlayActivity extends Activity {
        /** Called when the activity is first created. */
        private EditText filenamEditText;
        private MediaPlayer mediaPlayer;
        private String filename;
        private SurfaceView surfaceView;
        private final static String TAG="VodeoPlayActivity";
        private int prosition=0;
        
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            filenamEditText=(EditText) this.findViewById(R.id.filename);
            surfaceView=(SurfaceView)this.findViewById(R.id.surfaceview);
            surfaceView.getHolder().setFixedSize(176, 144);//设置分辨率
            surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置surfaceview不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前
            surfaceView.getHolder().addCallback(new SurceCallBack());//对surface对象的状态进行监听
            mediaPlayer=new MediaPlayer();
            
            ButtonOnClikListiner buttonOnClikListinero=new ButtonOnClikListiner();
            ImageButton start=(ImageButton) this.findViewById(R.id.play);
            ImageButton pause=(ImageButton) this.findViewById(R.id.pause);
            ImageButton stop=(ImageButton) this.findViewById(R.id.stop);
            ImageButton replay=(ImageButton) this.findViewById(R.id.reset);
            start.setOnClickListener(buttonOnClikListinero);
            pause.setOnClickListener(buttonOnClikListinero);
            stop.setOnClickListener(buttonOnClikListinero);
            replay.setOnClickListener(buttonOnClikListinero);
        }
        
        private final class ButtonOnClikListiner implements View.OnClickListener{
            @Override
            public void onClick(View v) {
                if(Environment.getExternalStorageState()==Environment.MEDIA_UNMOUNTED){
                    Toast.makeText(VodeoPlayActivity.this, "sd卡不存在", Toast.LENGTH_SHORT).show();
                    return;
                }
                filename=filenamEditText.getText().toString();
                switch (v.getId()) {
                case R.id.play:
                    play();
                    break;
                case R.id.pause:
                    if(mediaPlayer.isPlaying()){
                        mediaPlayer.pause();
                    }else{
                        mediaPlayer.start();
                    }
                    break;
                case R.id.reset:
                    if(mediaPlayer.isPlaying()){
                        mediaPlayer.seekTo(0);
                    }else{
                        play();
                    }
                    break;
                case R.id.stop:
                    if(mediaPlayer.isPlaying()){
                        mediaPlayer.stop();
                    }
                    break;
                }
            }  
        }
        
        private void play() {
            try {
                    File file=new File(Environment.getExternalStorageDirectory(),filename);
                    mediaPlayer.reset();//重置为初始状态
                    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);//设置音乐流的类型
                    mediaPlayer.setDisplay(surfaceView.getHolder());//设置video影片以surfaceviewholder播放
                    mediaPlayer.setDataSource(file.getAbsolutePath());//设置路径
                    mediaPlayer.prepare();//缓冲
                    mediaPlayer.start();//播放
                } catch (Exception e) {
                    Log.e(TAG, e.toString());
                    e.printStackTrace();
                }
        }
        
        private final class SurceCallBack implements SurfaceHolder.Callback{
            /**
             * 画面修改
             */
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width,
                    int height) {
                // TODO Auto-generated method stub
                
            }
    
            /**
             * 画面创建
             */
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                if(prosition>0&&filename!=null){
                    play();
                    mediaPlayer.seekTo(prosition);
                    prosition=0;
                }
                
            }
    
            /**
             * 画面销毁
             */
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if(mediaPlayer.isPlaying()){
                    prosition=mediaPlayer.getCurrentPosition();
                    mediaPlayer.stop();
                }
            }
        }
    }
    展开全文
  • 使用Camera与SurfaceView实现自定义拍照功能
  • Android之SurfaceView实现视频播放 1.案例一 布局文件: xml version="1.0" encoding="utf-8"?> LinearLayout xmlns:android=...
  • 一、概念 View在UI线程去更新自己; SurfaceView则在一个子线程中去更新自己 ...SurfaceView在新的线程中更新画面所以不会阻塞你的UI主线程,但是涉及到线程同步,需要SurfaceView中 thread处理. 触摸产生的动画...
  • Android自定义view--SurfaceView实现墨迹天气的风车效果 SurfaceView也是继承自View,它和我们以前接触到的View(Button、TextView等)最大的不同是,SurfaceView可以有一个单独的线程进行绘制,这个线程区别于...
  • 一、传统实现的基本步骤  1、MediaPlayer mediaPlayer1 = new MediaPlayer();  2、SurfaceView的getHolder()函数可以获取SurfaceHolder对象,Surface 就在SurfaceHolder对象内。 Surface第一次被创建时回...
  • SurfaceView也是继承自View,它和我们以前接触到的View(Button、TextView等)最大的不同是,SurfaceView可以有一个... SurfaceView实现通常是自定义,继承SurfaceView并实现SurfaceHolder.Callback接口。使用Surfa
  • SurfaceView SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。 surface是纵深排序(Z-ordered)的,这...
  • SurfaceView实现手势绘制和视频播放

    千次阅读 2016-02-23 11:43:10
    SurfaceView和View的主要区别: View主要适用于主动更新,SurfaceView主要适用于被动、频繁更新 View在主线程中对画面进行刷,...View在绘制是没有使用双缓冲机制,而SurfaceView在底层实现机制中已经实现了双缓冲机制
  • 首先创建一个SurfaceView,并实现两个接口 ----- SurfaceHolder.Callback和Runnable public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback , Runnable{ 在构造函数里面...
  • Android视图SurfaceView实现原理分析

    万次阅读 多人点赞 2013-03-16 16:57:30
    在Android系统中,有一种特殊的视图,称为...又由于不会占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输入得不到及时响应。在本文中,我们就详细分析SurfaceView实现原理。
  • 先看看实现效果: SurfaceView类介绍:  进入源码: public class SurfaceView extends View { public SurfaceView(Context context) { super((Context)null, (AttributeSet)null, 0, 0); throw new R
  • SurfaceView内嵌在Activity的视图树里提供一块用于绘制的表层。提供它的主要目的之一就是方便其他线程更新界面,对于UI有大量用户操作需要不断更新界面的需求提供了方便。Android中的自定义View也支持自定义绘制,...
  • 因为这个类实现了SurfaceHolder.Callback接口,所以回调参数直接this surfaceHolder.setFixedSize(320, 220);  // 显示的分辨率,不设置为视频默认 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_...
  • 对于基于摄像头的Android应用,实时取景是一个基本前提,通过前置或后置摄像头持续获取捕获到的内容,可以进一步做处理(人脸检测、美颜、滤镜等)。 所谓实时取景,简单说就是调用...是SDK自带的SurfaceView类而...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,899
精华内容 2,759
关键字:

创建surfaceview实现的接口