频道栏目
首页 > 程序开发 > 移动开发 > Android > 正文
安卓_多媒体 加载大图 画板 撕衣服 动画 音乐盒 视频播放
2016-10-19 09:23:41         来源:心志恒  
收藏   我要投稿

1.内容观察者

[1]内容观察者不是四大组件,就不需要在清单文件里面配置

实现的步骤

1)注册内容观察者

1.getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));

2)定义内容观察者

1.//定义内容观察者
2.  private class MyContentObserver extends ContentObserver{
3.
4.      public MyContentObserver(Handler handler) {
5.          super(handler);
6.      }
7.      //当我们观察的内容发生变化 这个方法就执行
8.      @Override
9.      public void onChange(boolean selfChange) {
10.         System.out.println("哈哈  数据库被人操作了");
11.         super.onChange(selfChange);
12.     }
13.     
14. }

3)内容观察者想要接收到通知,需要被操作的数据库自己主动发消息

1.getContext().getContentResolver().notifyChange(uri, null);

    //[2]注册内容观察者  参数二:如果是false 那么第一个参
    数的uri必须是一个精确的uri true:可以不用是一个精确的uri
    getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));

2.内容观察者来实现短信的监听

3.  @Override
4.  protected void onCreate(Bundle savedInstanceState) {
5.      super.onCreate(savedInstanceState);
6.      setContentView(R.layout.activity_main);
7.      //[1]注册内容观察者
8.      Uri uri = Uri.parse("content://sms/");
9.      getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
10.     
11. }
12. //定义内容观察者
13.     private class MyContentObserver extends ContentObserver{
14.         public MyContentObserver(Handler handler) {
15.             super(handler);
16.         }
17.         //当我们观察的内容发生变化 这个方法就执行
18.         @Override
19.         public void onChange(boolean selfChange) {
20.             Uri uri = Uri.parse("content://sms/");
21.             Cursor cursor = getContentResolver().query(uri, new String[]{"address","body","date"}, null, null, null);
22.             cursor.moveToFirst();
23.             String address = cursor.getString(cursor.getColumnIndex("address"));
24.             String body = cursor.getString(1);
25.             System.out.println("address:"+address+"~~~"+body);
26.         }
27.         
28.     }

3 计算机表示图形的几种方式

jpg :以良好质量保存 用于计算机

png:以高质量保存 用于计算机或者网络

bmp :以高质量保存 用于计算机 无损(没有警告压缩的)
图片大小 = 图片的总像素 * 每个像素大小

单色 :每个像素最多可以表示2种颜色. 只能表示黑 和 白.用二进制表示的化,那么只需要使用长度为1的二进制位来表示 ,那么占1/8byte

16色 :每个像素最多可以表示16种颜色,0~15 ,0000 -1111 那么只需要使用长度为4的二进制位来表示 ,那么一个像素占1/2byte

256色.每个像素最多可以表示256种颜色 0~255 ,0000 0000 -1111 1111 那么只需要使用长度为8,那么一个像素占1byte

24位: 16777215色

       R  :8位  1bye

       G  :8位  1byte

       B : 8位   1byte   那么每个像素占3byte

Android中表示颜色更加丰富.采用ARGB 一个占4byte

4.加载大(图片的分辨率)图片

10-16 02:11:10.443: I/dalvikvm-heap(22693): Forcing collection of SoftReferences for 30720012-byte allocation

图片大小 2400 * 3200      宽高都除以100     240 和320

手机大小:320 * 480 

计算缩放比:7  6   按照大的去缩放.

所以需要我们动态的获取手机的分辨率和图片的分辨率 在算出缩放比 

获取手机分辨率的2种方式

★使用过时的api

1.//[2]获取手机的分辨率   
2.      WindowManager wm  = (WindowManager) getSystemService(WINDOW_SERVICE);
3.      int width = wm.getDefaultDisplay().getWidth();
4.      int height = wm.getDefaultDisplay().getHeight();


   ★使用新的api

1.Point point = new Point();
2.      wm.getDefaultDisplay().getSize(point);
3.      int width = point.x;
4.      int height = point.y;
5.      System.out.println("手机的分辨率:"+width+"~~~~"+height);


    什么情况需要缩放加载大图片:图片的分辨率远远大于手机的分辨率.

 实现代码

public class MainActivity extends Activity {

    private ImageView iv;
    private int x;
    private int y;
    private int height;
    private int width;

    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv = (ImageView) findViewById(R.id.iv);
        // [1]获取手机分辨率
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        height = wm.getDefaultDisplay().getHeight();
        width = wm.getDefaultDisplay().getWidth();
        System.out.println(height + "---" + width);
        // [2]获取手机分辨率
//      Point point = new Point();
//      wm.getDefaultDisplay().getSize(point);
//      x = point.x;
//      y = point.y;
//      System.out.println(x + "---" + y);

    }

    public void click(View v) {

        /*
         * Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg");
         * iv.setImageBitmap(bitmap);
         */
        // [1]创建位图工厂配置参数
        BitmapFactory.Options opts = new Options();
        // [1.1]不去真正的解析位图 返回一个null(no bitmap) 但是还可以获取图片的宽高信息
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg", opts);

        // [1.2]获取图片宽和高
        int outWidth = opts.outWidth;
        int outHeight = opts.outHeight;
        System.out.println("图片宽"+outWidth);
        // [1.3]算出缩放比 图片的高/手机高 图片的宽/手机的宽 按照大的去缩放
        int scale = 1;
        int scalex = outWidth / width;
        int scaley = outHeight / height;
        System.out.println(scalex);
        if (scalex >= scaley && scalex > scale) {
            scale = scalex;

        } else if (scaley >= scalex && scaley > scale) {
            scale = scaley;

        }
        System.out.println("缩放比:"+scale);
        // [1.4]按照缩放比加载图片
        opts.inSampleSize = scale;
        // [1.5]按照这个缩放比解析位图,false时去解析位图
        opts.inJustDecodeBounds = false;
        // [0]展示图片
        Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg", opts);
        iv.setImageBitmap(bitmap);
    }
}

5.创建原图的副本

   想修改原图: 注意 原图不可以修改  所以我才创建原图的副本

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageView copy = (ImageView) findViewById(R.id.iv_copy);
        ImageView iv = (ImageView) findViewById(R.id.iv);
        //[1]把res下图片展示到iv上
        Bitmap srcbitmap = BitmapFactory.decodeResource(getResources(), R.drawable.qq);
        iv.setImageBitmap(srcbitmap);
        //[2]创建原图的副本  相当于我们创建了一个模板  相当于你有了一张白纸
        Bitmap copyBitmap = Bitmap.createBitmap(srcbitmap.getWidth(), srcbitmap.getHeight(), srcbitmap.getConfig());
        //[3.1]想作画需要一个画笔类 
        Paint paint = new Paint();
        //[3.2]想作画还需要一个画布   相当于把白纸铺到了画布上
        Canvas canvas = new Canvas(copyBitmap);
        //[3.3]就可以开始作画了  参考原图去作画 把原图的内容画到了白纸上
        canvas.drawBitmap(srcbitmap, new Matrix(), paint);
        copy.setImageBitmap(copyBitmap);
    }

}   

6.实现图形的特效

//[4.1]缩放
//matrix.setScale(1.5f, 1f);
//[4.2]位移
//matrix.setTranslate(4f, 1f);
//[4.3]旋转,中心坐标
//matrix.setRotate(25, srcbitmap.getWidth()/2, srcbitmap.getHeight()/2);
//[4.4]镜面,使用缩放和位移的一个组合就可以使用镜面, //postTranslate是在上一次的基础上进行在次修改  set是每次的操作都是最新的 会覆盖上一次的操作
//matrix.setScale(-1.0f, 1.0f);
//matrix.postTranslate(srcbitmap.getWidth(), 0);
//[4.5]倒影
matrix.setScale(1.0f, -1f);
matrix.postTranslate(0, srcbitmap.getHeight());
//[3.3]就可以开始作画了  参考原图去作画 把原图的内容画到了白纸上
canvas.drawBitmap(srcbitmap, matrix, paint);
copy.setImageBitmap(copyBitmap);

7.画画板案例

  想实现随手涂鸦 实际上就是在屏幕上不停的画线就可以了


1.
2.
3.  private Bitmap copyBimap;
4.  private Bitmap srcBitmap;
5.  private ImageView iv;
6.  private Paint paint;
7.  private Canvas canvas;
8.
9.  @Override
10. protected void onCreate(Bundle savedInstanceState) {
11.     super.onCreate(savedInstanceState);
12.     setContentView(R.layout.activity_main);
13.     // [1]找到iv 用来展示我们画的内容
14.     iv = (ImageView) findViewById(R.id.iv);
15.
16.     // [2]先获取bg.png的原图
17.     srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
18.
19.     copyBimap = Bitmap.createBitmap(srcBitmap.getWidth(),
20.             srcBitmap.getHeight(), srcBitmap.getConfig());
21.     // [3.1]创建画笔类
22.     paint = new Paint();
23.     // [3.2]创建一个画布类 相当于把白纸铺到了画布上
24.     canvas = new Canvas(copyBimap);
25.     // [3.3]开始作画 当32行代码执行完毕后 白纸上就有内容了
26.     canvas.drawBitmap(srcBitmap, new Matrix(), paint);
27.     // [3.4]画一条线 线由2个点确定一条线
28.     // canvas.drawLine(20, 30, 40, 70, paint);
29.     // [4]把质的内容展示到iv上
30.     iv.setImageBitmap(copyBimap);
31.     // [5]给iv设置触摸事件
32.     iv.setOnTouchListener(new OnTouchListener() {
33.         float startX = 0;
34.         float startY = 0;
35.
36.         @Override
37.         public boolean onTouch(View v, MotionEvent event) {
38.             // [6]具体判断一下触摸事件的类型
39.             int action = event.getAction();
40.             switch (action) {
41.             case MotionEvent.ACTION_DOWN: // 按下
42.                 // [7]获取手指按下的坐标
43.                 startX = event.getX();
44.                 startY = event.getY();
45.                 System.out.println("按下:" + startX + "~~~~" + startY);
46.                 break;
47.             case MotionEvent.ACTION_MOVE: // 移动
48.                 // [8]获取移动后的坐标
49.                 float stopX = event.getX();
50.                 float stopY = event.getY();
51.                 // [9]不停的画线
52.                 canvas.drawLine(startX, startY, stopX, stopY, paint);
53.                 System.out.println("移动:" + stopX + "~~~~" + stopY);
54.                 // [10]更新iv
55.                 iv.setImageBitmap(copyBimap);
56.                 // [11]更新一下开始的坐标 startX startY
57.                 startX = stopX;
58.                 startY = stopY;
59.
60.                 break;
61.
62.             case MotionEvent.ACTION_UP: // 抬起
63.
64.                 break;
65.             }
66.
67.             // 如果返回值是true,才能看到画上的线条
68.             return true;
69.         }
70.     });
71.
72. }
73.
74. // 点击按钮让画笔变红色
75. public void click1(View v) {
76.     paint.setColor(Color.RED);
77. }
78.
79. // 点击按钮让画笔加粗
80. public void click2(View v) {
81.     paint.setStrokeWidth(19);
82. }
83. 
84. //点击按钮保存 大作
85. public void click3(View v) {
86.     try {
87.         File file = new File(Environment.getExternalStorageDirectory().getPath(),"dazuo.png");
88.         FileOutputStream fos = new FileOutputStream(file);
89.         //参1:保存图片的格式   参数2:quality 质量
90.         copyBimap.compress(CompressFormat.PNG, 100, fos);
91.         fos.close();
92.         Toast.makeText(getApplicationContext(), "sucess", 1).show();
93.     } catch (Exception e) {
94.         e.printStackTrace();
95.     }
96. }


  触摸事件分 按下 移动 和 抬起  ★:触摸事件的返回值要返回true ★ 画完线后 要记得更新iv.

8.撕衣服

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final ImageView iv = (ImageView) findViewById(R.id.iv);
        Bitmap prebitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.pre19);
        // 创建模板
        final Bitmap srcBitmap = Bitmap.createBitmap(prebitmap.getWidth(),
                prebitmap.getHeight(), prebitmap.getConfig());
        // 画笔
        Paint paint = new Paint();
        // 画布
        Canvas canvas = new Canvas(srcBitmap);
        canvas.drawBitmap(prebitmap, new Matrix(), paint);
        // 把图展示到iv上
        iv.setImageBitmap(srcBitmap);
        // 设置触摸事件
        iv.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();

                switch (action) {

                case MotionEvent.ACTION_MOVE:
                    for (int i = -15; i < 15; i++) {
                        for (int j = -15; j < 15; j++) {
                            //要try -catch
                            try {
                                srcBitmap.setPixel((int) event.getX() + i,
                                        (int) event.getY() + j, Color.TRANSPARENT);
                                iv.setImageBitmap(srcBitmap);
                            } catch (Exception e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    }
                    break;
                }
                return true;
            }
        });

    }

}

9.百度音乐盒

百度音乐盒涉及到的知识点: mediaplayer 与mediaplayer相关的方法 服务 bindservice开启服务获取服务的中间人对象. handler传递多个数据 Timer seekBar;

………….

public class MusicService extends Service {

    private MediaPlayer mediaPlayer;
    private Timer timer;
    private TimerTask task;

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return new Mybinder();
    }

    @Override
    public void onCreate() {
        mediaPlayer = new MediaPlayer();

        super.onCreate();
    }

    // [1]调用播放音乐的方法
    public void playMusic() {
        // [1.1]设置播放路径
        try {
            mediaPlayer.setDataSource("/mnt/sdcard/Baby.mp3");
            mediaPlayer.prepare();
            mediaPlayer.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // [1.2]调用暂停音乐的方法
    public void pauseMusic() {
        mediaPlayer.pause();
    }
    // [1.3] 继续播放音乐的方法
    public void rePlayMusic() {
        mediaPlayer.start();
    }

    // [3]更新进度条的方法
    public void updateseekbar() {
        // [3.1]获取当前歌曲的总时长
        final int duration = mediaPlayer.getDuration();
        timer = new Timer();
        task = new TimerTask() {
            @Override
            public void run() {
                int currentPosition = mediaPlayer.getCurrentPosition();
                // [4]更新进度条
                Message message = Message.obtain();
                // [4.1]准备bundle
                Bundle bundle = new Bundle();
                bundle.putInt("duration", duration);
                bundle.putInt("currentPosition", currentPosition);
                // [4.2]使用msg携带多条数据
                message.setData(bundle);
                // [4.3]发消息 maniActivity的handlemessage方法就会执行
                MainActivity.handler.sendMessage(message);
                // [4.4]给mediaplayer设置播放完成的监听
                mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        System.out.println("歌曲播放完成了");
                        timer.cancel();
                        task.cancel();
                    }
                });
            }
        };
        // [3.4]方法意思再隔1秒后,每一秒执行一次,更新进度条
        timer.schedule(task, 1000, 1000);

    }

    // 设置歌曲播放位置的方法
    public void playSeekToPosition(int position) {
        mediaPlayer.seekTo(position);
    }

    private class Mybinder extends Binder implements Iservice {
        // [2]调用播放音乐的方法
        @Override
        public void callplayMusic() {
            playMusic();

        }

        // [2.1]调用暂停音乐的方法
        @Override
        public void callpauseMusic() {
            pauseMusic();

        }

        // [2.2]调用继续播放音乐的方法
        @Override
        public void callreplayMusic() {
            rePlayMusic();

        }

        @Override
        public void callplaySeekToPosition(int position) {
            playSeekToPosition(position);
        }

    }

}

……………………..

MainActivity代码

……………………….

public class MainActivity extends Activity {

    private MediaPlayer player;
    private Iservice iservice;
    private Myconn conn;
    private static SeekBar sb;
    // [5]这个方法处理消息的时候执行
    public static Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // [5.1]获取发消息携带的数据 数据是怎么发的 就怎么取 数据发的是什么类型就取什么类型
            Bundle bundle = msg.getData();
            // [5.2]获取歌曲的总时长和 当前进度
            int duration = bundle.getInt("duration");
            int currentPosition = bundle.getInt("currentPosition");
            // [5.3]更新进度条
            sb.setMax(duration);
            sb.setProgress(currentPosition);
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // [1]调用startservice 保证服务在后台长期运行
        Intent intent = new Intent(this, MusicService.class);
        startService(intent);
        // [2]想点击按钮的时候 调用服务里面的方法 获取我们在服务内部定义的中间人对象
        conn = new Myconn();
        bindService(intent, conn, BIND_AUTO_CREATE);

        sb = (SeekBar) findViewById(R.id.sb_1);
        // [4]给seekbar设置监听
        sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
            // [4.1]当拖动进度条停止 执行
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                // [4.11]在这个方法里面实现拖动到哪就播放歌曲对应的位置
                iservice.callplaySeekToPosition(sb.getProgress());
            }

            // [4.2]刚开始托
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress,
                    boolean fromUser) {

            }
        });
    }

    // 监视服务的状态
    private class Myconn implements ServiceConnection {

        // 当连接成功后执行
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iservice = (Iservice) service;
        }

        // 当失去连接执行
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }

    }

    // 当Activity销毁的时候 解绑服务
    @Override
    protected void onDestroy() {
        unbindService(conn);
        super.onDestroy();
    }

    public void click1(View v) {
        iservice.callplayMusic();
    }

    public void click2(View v) {
        iservice.callpauseMusic();

    }

    public void click3(View v) {
        iservice.callreplayMusic();

    }

}

……………………………..

定义接口

………………..

public interface Iservice {
    public void callplayMusic();
    public void callpauseMusic();
    public void callreplayMusic();
    public void callplaySeekToPosition(int position);
}

10.播放网络音乐

//[3]播放sd卡里面的小苹果音乐
mediaPlayer = new MediaPlayer();
//[4]设置播放视频的路径
mediaPlayer.setDataSource("https://192.168.101.88:8080/cc.mp4");
//[5]准备播放
mediaPlayer.prepare();      //同步   比如张三喊李四吃饭
mediaPlayer.prepareAsync(); //异步   张三喊李四吃饭 

//[7]设置一个准备完成的一个监听 
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
//当这个方法执行说明我们要播放的数据一定缓冲好了
    @Override
    public void onPrepared(MediaPlayer mp) {
        //[4]播放音乐
        mediaPlayer.start();
        //[5]继续上次的位置继续播放
    }

11.视频的播放

 [1] 播放视频要比播放音频多一个画面

 [2] 这个画面的展示使用surfaceView(表面的view)

 [3]surfaceView这个类是一个重量级控件,  

 [4]播放视频的代码

……………………………………

new Thread() {
        public void run() {
            SystemClock.sleep(500);
        }
}.start();

休眠会能播放

……………………………………..

public class MainActivity extends Activity {

    private MediaPlayer mediaPlayer;
    private int currentPosition;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SurfaceView sf = (SurfaceView) findViewById(R.id.sf);
        // [1.1]展示画面
        SurfaceHolder holder = sf.getHolder();

        // [1.2]为了确保surfaceview完全实例化 不采用睡眠的方式, holder内部通过一个监听来维护
        holder.addCallback(new Callback() {

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                try {
                    mediaPlayer = new MediaPlayer();
                    mediaPlayer
                            .setDataSource("https://192.168.101.72:8080/cc.mp4");
                    // [2.1]从网络获取
                    mediaPlayer.prepareAsync();
                    // [2.2]把播放的画面数据放到sfv上 SurfaceHolder 是用来维护视频表面的数据
                    // 这个实例通过surfaceView来获取
                    mediaPlayer.setDisplay(holder);
                    // [2.3]设置一个准备完成的一个监听
                    mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
                        // 当这个方法执行说明我们要播放的数据一定缓冲好了
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            // [2.4]播放音乐
                            mediaPlayer.start();
                            // [2.5]继续上次的位置继续播放
                            mediaPlayer.seekTo(currentPosition);
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format,
                    int width, int height) {

            }

            // 当surfaceView 表面看不见 就代表销毁
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                // [1.21]获取当前视频播放的位置
                if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                    currentPosition = mediaPlayer.getCurrentPosition();
                    mediaPlayer.stop();
                    mediaPlayer.release();
                }

            }
        });

    }

}

12 videoView控件的使用

 播放视频的代码 

//[1]找到控件 播放视频
VideoView vv = (VideoView) findViewById(R.id.vv);
//[2]设置播放的数据原 
vv.setVideoPath("https://192.168.101.88:8080/cc.mp4");
//[3]播放视频
vv.start();

底层实际上就是对mediaplayer和surfaceview的封装.
mediaplayer播放视频只支持mp4 或者3gp格式.avi  rmvb不支持

13.vitamio 框架

   类库 相当于jar

   使用vitamio步骤


1 引入vitamio框架  加入library

2 在布局中定义VideoView
   



3 mainactivity代码
   插件vitamio框架检查是否可用
   if (!LibsChecker.checkVitamioLibs(this)) {
        return;
    }

    final VideoView vv = (VideoView) findViewById(R.id.vv);
    vv.setVideoPath("https://192.168.1.2:8080/haha.avi");
    vv.setOnPreparedListener(new OnPreparedListener() {

        @Override
        public void onPrepared(MediaPlayer mp) {
            vv.start();

        }
    });
    //设置video的控制器
    vv.setMediaController(new MediaController(this));


 4 一定要在清单文件初始化InitActivity
    

……………………………………………..

解码器 都使用的是另外一个开源项目:ffmpeg  

播放视频三种方式 [1]surfaceview [2]videoView  [3]viamio  实际开发中用哪个. 
点击复制链接 与好友分享!回本站首页
上一篇:android之帧动画和补间动画
下一篇:安卓_Fragment通信 menu菜单 补间动画 属性动画 通知栏
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站