欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SurfaceView

程序员文章站 2022-03-29 19:29:08
...

一.使用SurfaceView播放视频

1.布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">
   <SurfaceView
       android:layout_width="match_parent"
       android:layout_height="400dp"
       android:id="@+id/surfaceview"></SurfaceView>
    <SeekBar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:id="@+id/progressbar"></SeekBar>


</LinearLayout>

2.MainActivity代码

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
    private SurfaceView surfaceview;
    private SeekBar progressbar;
    MediaPlayer mediaPlayer = new MediaPlayer();
    SurfaceHolder surfaceHolder;
    Timer timer = new Timer();
    String video;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        surfaceview = (SurfaceView) findViewById(R.id.surfaceview);
        progressbar = (SeekBar) findViewById(R.id.progressbar);
        surfaceHolder = surfaceview.getHolder();
        surfaceHolder.addCallback(this);

        Intent intent = getIntent();
//        video = intent.getStringExtra("video");
        Toast.makeText(this,""+video,Toast.LENGTH_SHORT).show();
        try {
            initplayer();
        } catch (IOException e) {
            e.printStackTrace();
        }
        progressbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                if (b){
                    mediaPlayer.seekTo(seekBar.getProgress());
                }

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

    }

    private void initplayer() throws IOException {
        if (mediaPlayer!=null){
            mediaPlayer.reset();
            mediaPlayer.setDataSource("http://tvideo.spriteapp.cn/video/2019/0910/5d7691e370b3c_wpd.mp4");
            mediaPlayer.setDataSource(video);
            mediaPlayer.prepareAsync();
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
               @Override
               public void onPrepared(MediaPlayer mediaPlayer) {
                   mediaPlayer.start();
                   int videoWidth = mediaPlayer.getVideoWidth();
               }
           });

            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    int duration = mediaPlayer.getDuration();
                    int currentPosition = mediaPlayer.getCurrentPosition();
                    int i = currentPosition * 100 / duration;
                    progressbar.setProgress(i);
                }
            },0,1000);

        }

    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        Log.d("zyj", "创建了: ");
        mediaPlayer.setDisplay(surfaceHolder);
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        Log.d("zyj", "改变了: ");

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        Log.d("zyj", "销毁了: ");
        if (mediaPlayer!=null){
            mediaPlayer.release();
            mediaPlayer=null;
        }
        if (timer!=null){
            timer.cancel();
        }

    }
}

二.使用SurfaceView绘制各种图形

1.绘制各种图形

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
    private SurfaceView surfaceview;
    private SurfaceHolder surfaceHolder;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        surfaceview = (SurfaceView) findViewById(R.id.surfaceview);
        surfaceHolder = surfaceview.getHolder();
        surfaceHolder.addCallback(this);
    }

    //创建
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        //TODO:1.画笔
        Paint paint = new Paint();
        //TODO:2.设置笔的颜色
        paint.setColor(Color.BLUE);
        //设置画笔样式,fill是实心,stoke是空心,fill_or_stoke:同时实心与空心
//        paint.setStyle(Paint.Style.FILL);
//        paint.getTextSize(float textsize)//设置绘制文字的字号大小
//        paint.setAntiAlias(true);//抗锯齿
        //TODO:3.设置线条宽度
        paint.setStrokeWidth(20);

        ////TODO:3.画布
        Canvas canvas = surfaceHolder.lockCanvas();//锁定画布
        canvas.drawColor(Color.WHITE);//设置画布颜色
        //画一条线
        canvas.drawLine(0,0,500,500,paint);
        //画一个点
        canvas.drawPoint(300,300,paint);
        //画一个圆形(oval是椭圆)
        canvas.drawOval(200,200,400,400,paint);
        //画文字
        /**
         * 参数1:要从第几个文字开始绘制
         * 参数2:要绘制到第几个文字
         * 参数3:文本的X轴的开始位置
         * 参数4:文本的Y轴的结束位置
         * 参数5 画笔对象
         */
        canvas.drawText("开始写字了",50,50,paint);
        /**
         * 参数1:路径
         * 参数2:距离路径开始位置的偏移量
         * 参数3:距离路径上下的偏移量
         * 参数4:画笔对象
         */
//        canvas.drawTextOnPath("123456789",path,0,-50,paint);

        //画矩形
        /**
         * 参数1:float left
         * 参数2:float top
         * 参数3:float right
         * 参数4:float buttom
         */
        canvas.drawRect(100,100,200,200,paint);
        //画圆角矩形
        RectF rectF = new RectF(80, 260, 200, 300);//设置个新的长方形
        canvas.drawRoundRect(rectF,20,5,paint);//第二个参数是X半径,第三个参数是Y半径

        //画扇形
        canvas.drawArc(500,500,700,700,20,180,true,paint);
        surfaceHolder.unlockCanvasAndPost(canvas);//解锁画布
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

    }
}

三.播放音乐的时候,滚动歌词

1. xml布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MusicActivity"
    android:orientation="vertical">
    <SurfaceView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/surfaceview3"></SurfaceView>

</LinearLayout>

2.MainActivity中代码

public class MusicActivity extends AppCompatActivity implements SurfaceHolder.Callback {
    private Timer timer = new Timer();
    private SurfaceView surfaceview3;
    ArrayList<Music>list = new ArrayList<>();
    private MediaPlayer mediaPlayer = new MediaPlayer();
    SurfaceHolder surfaceHolder;
    int position;//正在显示的歌词的下标

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_music);
        surfaceview3 = (SurfaceView) findViewById(R.id.surfaceview3);
        surfaceHolder = surfaceview3.getHolder();
        surfaceHolder.addCallback(this);

        if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){
            requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE},100);
        }
        try {
            initCi();   //解析歌词
            initPlayer(); //播放音乐
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void initPlayer() throws IOException {
        if (mediaPlayer!=null){
            mediaPlayer.reset();
            mediaPlayer.setDataSource("/sdcard/凤凰传奇 - 最炫民族风(Live).mp3");
            mediaPlayer.prepareAsync();
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(final MediaPlayer mediaPlayer) {
                    mediaPlayer.start();
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                             if (list.size()>0&& position+1<list.size()){
                                 int currentPosition = mediaPlayer.getCurrentPosition();
                                 if (currentPosition>=list.get(position+1).getStart_time()) {
                                     position++;
                                 }
                             }
                        }
                    },0,100);
                }
            });
        }
    }

    private void initCi() throws IOException {
        //TODO 1:读取SD卡的歌词 json串
        FileInputStream fileInputStream = new FileInputStream("/sdcard/最炫民族风");
        StringBuffer stringBuffer = new StringBuffer();
        byte[] bytes = new byte[1024];
        int len=0;
        while((len=fileInputStream.read(bytes))!=-1){
            stringBuffer.append(new String(bytes,0,len));
        }
        //TODO 2:解析json串获得整首歌的歌词
        Gson gson = new Gson();
        Bean bean = gson.fromJson(stringBuffer.toString(), Bean.class);
        String lyric = bean.getLrc().getLyric();
        Log.d("zjy", "initCi: "+lyric);
        //TODO 3:按照\n进行切割得到每句歌词
        String[] split = lyric.split("\n");
        for (int i = 1; i < split.length; i++) {
            String replace = split[i].replace("[", "")
                    .replaceFirst(":","@")//只替换第一个
                    .replace(".","@")
                    .replace("]","@");

            Log.d("zjy", "initCi: "+replace);
            String[] split1 = replace.split("@");
            int  start_time= Integer.parseInt(split1[0])*60*1000+Integer.parseInt(split1[1])*1000+Integer.parseInt(split1[2]);
            if (split1.length>=4){
                list.add(new Music(split1[3],start_time));
            }
        }
        //TODO 4:打印集合数据
        for (Music music:list){
            Log.d("zjy", "initCi: "+music);
        }

    }

    @Override
    public void surfaceCreated(final SurfaceHolder surfaceHolder) {
          new Thread(new Runnable() {
              @Override
              public void run() {
                  Paint paint = new Paint();
                  paint.setColor(Color.RED);
                  paint.setTextSize(40);
                  while (true){
                      Canvas canvas = surfaceHolder.lockCanvas();
                      canvas.drawColor(Color.WHITE);
                      canvas.drawText(list.get(position).getText(),200,300,paint);
                      surfaceHolder.unlockCanvasAndPost(canvas);
                  }
              }
          }).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

    }
}

3.Bean类(歌词类)

package com.example.app2.bean;

public class Bean {

    /**
     * sgc : false
     * sfy : false
     * qfy : false
     * lyricUser : {"id":29418062,"status":0,"demand":0,"userid":12907497,"nickname":"Simfre","uptime":1441503572343}
     * lrc : {"version":5,"lyric":"[by:简单de频率]\n[00:00.000] 作曲 : 张超\n[00:01.000] 作词 : 张超\n[00:22.600]苍茫的天涯是我的爱\n[00:26.280]绵绵的青山脚下花正开\n[00:30.130]什么样的节奏是最呀最摇摆\n[00:33.880]什么样的歌声才是最开怀\n[00:37.750]弯弯的河水从天上来\n[00:41.310]流向那万紫千红一片海\n[00:45.330]火辣辣的歌谣是我们的期待\n[00:48.880]一路边走边唱才是最自在\n[00:52.630]我们要唱就要唱得最痛快\n[00:56.610]你是我天边最美的云彩\n[01:00.280]让我用心把你留下来(留下来)\n[01:04.340]悠悠的唱着最炫的民族风\n[01:07.840]让爱卷走所有的尘埃\n[01:10.470](我知道)你是我心中最美的云彩\n[01:15.380]斟满美酒让你留下来(留下来)\n[01:19.380]永远都唱着最炫的民族风\n[01:22.760]是整片天空最美的姿态\n[01:26.700]哟啦啦呵啦呗\n[01:28.520]伊啦嗦啦呵啦呗呀\n[01:30.700]我听见你心中动人的天籁\n[01:34.260]登上天外云霄的舞台\n[01:37.530]\n[01:53.250]苍茫的天涯是我的爱\n[01:56.940]绵绵的青山脚下花正开\n[02:00.820]什么样的节奏是最呀最摇摆\n[02:04.570]什么样的歌声才是最开怀\n[02:08.440]弯弯的河水从天上来\n[02:12.000]流向那万紫千红一片海\n[02:15.810]火辣辣的歌谣是我们的期待\n[02:19.620]一路边走边唱才是最自在\n[02:23.310]我们要唱就要唱得最痛快\n[02:27.220]你是我天边最美的云彩\n[02:30.920]让我用心把你留下来(留下来)\n[02:34.920]悠悠的唱着最炫的民族风\n[02:38.410]让爱卷走所有的尘埃\n[02:41.410](我知道)你是我心中最美的云彩\n[02:46.210]斟满美酒让你留下来(留下来)\n[02:50.140]永远都唱着最炫的民族风\n[02:53.460]是整片天空最美的姿态\n[02:57.810]\n[03:18.290]你是我天边最美的云彩\n[03:21.910]让我用心把你留下来(留下来)\n[03:26.030]悠悠的唱着最炫的民族风\n[03:29.510]让爱卷走所有的尘埃\n[03:32.260](我知道)你是我心中最美的云彩\n[03:37.010]斟满美酒让你留下来(留下来)\n[03:41.070]永远都唱着最炫的民族风\n[03:44.570]是整片天空最美的姿态\n[03:48.990]\n[03:50.300]我听见你心中那动人的天籁\n[03:53.990]就忽如一夜春风袭来满面桃花开\n[03:57.860]我忍不住去采 我忍不住去摘\n[04:01.620]我敞开胸怀为你等待\n[04:04.340]\n[04:05.840]你是我天边最美的云彩\n[04:09.280]让我用心把你留下来\n[04:13.010]悠悠的唱着最炫的民族风\n[04:16.750]让爱卷走所有的尘埃\n[04:19.500](我知道)你是我心中最美的云彩\n[04:24.250]斟满美酒让你留下来(留下来)\n[04:28.380]永远都唱着最炫的民族风\n[04:31.750]是整片天空最美的姿态\n[04:36.190]\n"}
     * klyric : {"version":0,"lyric":null}
     * tlyric : {"version":0,"lyric":null}
     * code : 200
     */

    private boolean sgc;
    private boolean sfy;
    private boolean qfy;
    private LyricUserBean lyricUser;
    private LrcBean lrc;
    private KlyricBean klyric;
    private TlyricBean tlyric;
    private int code;

    public boolean isSgc() {
        return sgc;
    }

    public void setSgc(boolean sgc) {
        this.sgc = sgc;
    }

    public boolean isSfy() {
        return sfy;
    }

    public void setSfy(boolean sfy) {
        this.sfy = sfy;
    }

    public boolean isQfy() {
        return qfy;
    }

    public void setQfy(boolean qfy) {
        this.qfy = qfy;
    }

    public LyricUserBean getLyricUser() {
        return lyricUser;
    }

    public void setLyricUser(LyricUserBean lyricUser) {
        this.lyricUser = lyricUser;
    }

    public LrcBean getLrc() {
        return lrc;
    }

    public void setLrc(LrcBean lrc) {
        this.lrc = lrc;
    }

    public KlyricBean getKlyric() {
        return klyric;
    }

    public void setKlyric(KlyricBean klyric) {
        this.klyric = klyric;
    }

    public TlyricBean getTlyric() {
        return tlyric;
    }

    public void setTlyric(TlyricBean tlyric) {
        this.tlyric = tlyric;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public static class LyricUserBean {
        /**
         * id : 29418062
         * status : 0
         * demand : 0
         * userid : 12907497
         * nickname : Simfre
         * uptime : 1441503572343
         */

        private int id;
        private int status;
        private int demand;
        private int userid;
        private String nickname;
        private long uptime;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public int getStatus() {
            return status;
        }

        public void setStatus(int status) {
            this.status = status;
        }

        public int getDemand() {
            return demand;
        }

        public void setDemand(int demand) {
            this.demand = demand;
        }

        public int getUserid() {
            return userid;
        }

        public void setUserid(int userid) {
            this.userid = userid;
        }

        public String getNickname() {
            return nickname;
        }

        public void setNickname(String nickname) {
            this.nickname = nickname;
        }

        public long getUptime() {
            return uptime;
        }

        public void setUptime(long uptime) {
            this.uptime = uptime;
        }
    }

    public static class LrcBean {
        /**
         * version : 5
         * lyric : [by:简单de频率]
         [00:00.000] 作曲 : 张超
         [00:01.000] 作词 : 张超
         [00:22.600]苍茫的天涯是我的爱
         [00:26.280]绵绵的青山脚下花正开
         [00:30.130]什么样的节奏是最呀最摇摆
         [00:33.880]什么样的歌声才是最开怀
         [00:37.750]弯弯的河水从天上来
         [00:41.310]流向那万紫千红一片海
         [00:45.330]火辣辣的歌谣是我们的期待
         [00:48.880]一路边走边唱才是最自在
         [00:52.630]我们要唱就要唱得最痛快
         [00:56.610]你是我天边最美的云彩
         [01:00.280]让我用心把你留下来(留下来)
         [01:04.340]悠悠的唱着最炫的民族风
         [01:07.840]让爱卷走所有的尘埃
         [01:10.470](我知道)你是我心中最美的云彩
         [01:15.380]斟满美酒让你留下来(留下来)
         [01:19.380]永远都唱着最炫的民族风
         [01:22.760]是整片天空最美的姿态
         [01:26.700]哟啦啦呵啦呗
         [01:28.520]伊啦嗦啦呵啦呗呀
         [01:30.700]我听见你心中动人的天籁
         [01:34.260]登上天外云霄的舞台
         [01:37.530]
         [01:53.250]苍茫的天涯是我的爱
         [01:56.940]绵绵的青山脚下花正开
         [02:00.820]什么样的节奏是最呀最摇摆
         [02:04.570]什么样的歌声才是最开怀
         [02:08.440]弯弯的河水从天上来
         [02:12.000]流向那万紫千红一片海
         [02:15.810]火辣辣的歌谣是我们的期待
         [02:19.620]一路边走边唱才是最自在
         [02:23.310]我们要唱就要唱得最痛快
         [02:27.220]你是我天边最美的云彩
         [02:30.920]让我用心把你留下来(留下来)
         [02:34.920]悠悠的唱着最炫的民族风
         [02:38.410]让爱卷走所有的尘埃
         [02:41.410](我知道)你是我心中最美的云彩
         [02:46.210]斟满美酒让你留下来(留下来)
         [02:50.140]永远都唱着最炫的民族风
         [02:53.460]是整片天空最美的姿态
         [02:57.810]
         [03:18.290]你是我天边最美的云彩
         [03:21.910]让我用心把你留下来(留下来)
         [03:26.030]悠悠的唱着最炫的民族风
         [03:29.510]让爱卷走所有的尘埃
         [03:32.260](我知道)你是我心中最美的云彩
         [03:37.010]斟满美酒让你留下来(留下来)
         [03:41.070]永远都唱着最炫的民族风
         [03:44.570]是整片天空最美的姿态
         [03:48.990]
         [03:50.300]我听见你心中那动人的天籁
         [03:53.990]就忽如一夜春风袭来满面桃花开
         [03:57.860]我忍不住去采 我忍不住去摘
         [04:01.620]我敞开胸怀为你等待
         [04:04.340]
         [04:05.840]你是我天边最美的云彩
         [04:09.280]让我用心把你留下来
         [04:13.010]悠悠的唱着最炫的民族风
         [04:16.750]让爱卷走所有的尘埃
         [04:19.500](我知道)你是我心中最美的云彩
         [04:24.250]斟满美酒让你留下来(留下来)
         [04:28.380]永远都唱着最炫的民族风
         [04:31.750]是整片天空最美的姿态
         [04:36.190]

         */

        private int version;
        private String lyric;

        public int getVersion() {
            return version;
        }

        public void setVersion(int version) {
            this.version = version;
        }

        public String getLyric() {
            return lyric;
        }

        public void setLyric(String lyric) {
            this.lyric = lyric;
        }
    }

    public static class KlyricBean {
        /**
         * version : 0
         * lyric : null
         */

        private int version;
        private Object lyric;

        public int getVersion() {
            return version;
        }

        public void setVersion(int version) {
            this.version = version;
        }

        public Object getLyric() {
            return lyric;
        }

        public void setLyric(Object lyric) {
            this.lyric = lyric;
        }
    }

    public static class TlyricBean {
        /**
         * version : 0
         * lyric : null
         */

        private int version;
        private Object lyric;

        public int getVersion() {
            return version;
        }

        public void setVersion(int version) {
            this.version = version;
        }

        public Object getLyric() {
            return lyric;
        }

        public void setLyric(Object lyric) {
            this.lyric = lyric;
        }
    }
}

4.实体类

package com.example.app2.entity;

public class Music {
    private String text;
    private long start_time;

    public Music(String text, long start_time) {
        this.text = text;
        this.start_time = start_time;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public long getStart_time() {
        return start_time;
    }

    public void setStart_time(long start_time) {
        this.start_time = start_time;
    }

    @Override
    public String toString() {
        return "Music{" +
                "text='" + text + '\'' +
                ", start_time=" + start_time +
                '}';
    }
}