Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android基礎知識:Day09 多媒體編程

Android基礎知識:Day09 多媒體編程

編輯:關於Android編程

一、對話框

1. 確定取消對話框

創建對話框構建器對象,類似工廠模式

AlertDialog.Builder builder = new Builder(this);

設置標題和正文

builder.setTitle("警告");
builder.setMessage("若練此功,必先自宮");

設置確定和取消按鈕

builder.setPositiveButton("現在自宮", new OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {
        Toast.makeText(MainActivity.this, "恭喜你自宮成功,現在程序退出", 0).show();
    }
});

builder.setNegativeButton("下次再說", new OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {
        Toast.makeText(MainActivity.this, "若不自宮,一定不成功", 0).show();
    }
});

使用構建器創建出對話框對象

AlertDialog ad = builder.create();
ad.show();

2. 單選對話框

創建對話框對象

AlertDialog.Builder builder = new Builder(this);
builder.setTitle("選擇你的性別");

定義單選選項

final String[] items = new String[]{
        "男", "女", "其他"
};
// -1表示默認選擇
builder.setSingleChoiceItems(items, -1, new OnClickListener() {

    // which表示點擊的是哪一個選項
    @Override
    public void onClick(DialogInterface dialog, int which) {
        Toast.makeText(MainActivity.this, "您選擇了" + items[which], 0).show();
        // 對話框消失
        dialog.dismiss();
    }
});

builder.show();

3. 多選對話框

定義多選的選項,因為可以多選,所以需要一個boolean數組來記錄哪些選項被選了

AlertDialog.Builder builder = new Builder(this);
builder.setTitle("請選擇你認為最帥的人");

final String[] items = new String[]{
        "趙帥哥",
        "趙師哥",
        "趙老師",
        "侃哥"
};

// true表示對應位置的選項被選了
final boolean[] checkedItems = new boolean[]{
        true,
        false,
        false,
        false,
};

builder.setMultiChoiceItems(items, checkedItems, new OnMultiChoiceClickListener() {
    // 點擊某個選項,如果該選項之前沒被選擇,那麼此時isChecked的值為true
    @Override
    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
        checkedItems[which] = isChecked;
    }
});

builder.setPositiveButton("確定", new OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {
        StringBuffer sb = new StringBuffer();
        for(int i = 0;i < items.length; i++){
            sb.append(checkedItems[i] ? items[i] + " " : "");
        }
        Toast.makeText(MainActivity.this, sb.toString(), 0).show();
    }
});
builder.show();

 

二、國際化

字符串國際化:只要在res文件夾下新建對應語言的values文件夾就好了 美國英文環境:values-en-rUS 中文環境為:values-zh 大陸地區中文環境: values-zh-cn

 

三、樣式與主題

樣式與主題定義方式一樣 樣式用於布局文件中的組件 主題用於Activity

 

四、多媒體編程

4.1 計算機圖片大小的計算

圖片大小 = 圖片的總像素 * 每個像素占用的大小 單色圖:每個像素占用1/8個字節 16色圖:每個像素占用1/2個字節 256色圖:每個像素占用1個字節 24位圖:每個像素占用3個字節

4.2 加載大圖片到內存

Android系統以ARGB表示每個像素,每個像素占用4個字節,所以很容易內存溢出,因此我們需要對圖片進行縮放

4.3 對圖片進行縮放

獲取屏幕寬高

Display dp = getWindowManager().getDefaultDisplay();
int screenWidth = dp.getWidth();
int screenHeight = dp.getHeight();

獲取圖片寬高

Options opts = new Options();
// 請求圖片屬性但不申請內存
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
int imageWidth = opts.outWidth;
int imageHeight = opts.outHeight;

圖片的寬高除以屏幕寬高,算出寬和高的縮放比例,取較大值作為圖片的縮放比例

int scale = 1;
int scaleX = imageWidth / screenWidth;
int scaleY = imageHeight / screenHeight;
if(scaleX >= scaleY && scaleX > 1){
    scale = scaleX;
}
else if(scaleY > scaleX && scaleY > 1){
    scale = scaleY;
}

按縮放比例加載圖片

// 設置縮放比例
opts.inSampleSize = scale;
// 為圖片申請內存
opts.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
iv.setImageBitmap(bm);

4.4 在內存中創建圖片的副本

直接加載的bitmap對象是只讀的,無法修改,要修改圖片只能在內存中創建出一個一模一樣的bitmap副本,然後修改副本

// 加載原圖
Bitmap srcBm = BitmapFactory.decodeFile("sdcard/photo3.jpg");
iv_src.setImageBitmap(srcBm);

// 創建與原圖大小一致的空白bitmap
Bitmap copyBm = Bitmap.createBitmap(srcBm.getWidth(), srcBm.getHeight(), srcBm.getConfig());
// 定義畫筆
Paint paint = new Paint();
// 把紙鋪在畫版上
Canvas canvas = new Canvas(copyBm);
// 把srcBm的內容繪制在copyBm上
canvas.drawBitmap(srcBm, new Matrix(), paint);

iv_copy.setImageBitmap(copyBm);

4.5 對圖片進行特效處理

首先定義一個矩陣對象

Matrix mt = new Matrix();

縮放效果

// x軸縮放1倍,y軸縮放0.5倍
mt.setScale(1, 0.5f);

旋轉效果

// 以圖片寬高的一半中心點為軸點,順時旋轉30度
mt.setRotate(30, copyBm.getWidth() / 2, copyBm.getHeight() / 2);

平移

// x軸坐標+10,y軸坐標+20
mt.setTranslate(10, 20);

鏡面

// 把X坐標都變成負數
mt.setScale(-1, 1);
// 圖片整體向右移
mt.postTranslate(copyBm.getWidth(), 0);

倒影

// 把Y坐標都變成負數
mt.setScale(1, -1);
// 圖片整體向下移
mt.postTranslate(0, copyBm.getHeight());

 

五、多媒體案例

5.1 畫畫板

功能:記錄用戶觸摸事件的XY坐標,繪制直線

給ImageView設置觸摸偵聽,得到用戶的觸摸事件,並獲知用戶觸摸ImageView的坐標

iv.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
        // 觸摸屏幕
        case MotionEvent.ACTION_DOWN:
            // 得到觸摸屏幕時手指的坐標
            startX = (int) event.getX();
            startY = (int) event.getY();
            break;
        // 在屏幕上滑動
        case MotionEvent.ACTION_MOVE:
            // 用戶滑動手指,坐標不斷的改變,獲取最新坐標
            int newX = (int) event.getX();
            int newY = (int) event.getY();
            // 用上次onTouch方法得到的坐標和本次得到的坐標繪制直線
            canvas.drawLine(startX, startY, newX, newY, paint);
            iv.setImageBitmap(copyBm);
            startX = newX;
            startY = newY;
            break;
        }
        return true;
    }
});

刷子效果,加粗畫筆

paint.setStrokeWidth(8);

調色板,改變畫筆顏色

paint.setColor(Color.GREEN);

保存圖片至SD卡

FileOutputStream fos = null;
try {
    fos = new FileOutputStream(new File("sdcard/dazuo.png"));
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
// 保存圖片
copyBm.compress(CompressFormat.PNG, 100, fos);
系統每次收到SD卡就緒廣播時,都會去遍歷sd卡的所有文件和文件夾,把遍歷到的所有多媒體文件都在MediaStore數據庫保存一個索引,這個索引包含多媒體文件的文件名、路徑、大小 圖庫每次打開時,並不會去遍歷sd卡獲取圖片,而是通過內容提供者從MediaStore數據庫中獲取圖片的信息,然後讀取該圖片

系統開機或者點擊加載sd卡按鈕時,系統會發送sd卡就緒廣播,我們也可以手動發送就緒廣播

Intent intent = new Intent();
intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));
sendBroadcast(intent);

5.2 撕衣服

原理:把穿內衣和穿外衣的照片重疊顯示,內衣照在下面,用戶滑動屏幕時,觸摸的是外衣照,把手指經過的像素都置為透明,內衣照就顯示出來了

給屏幕設置移動監聽,把指定的像素設置為透明

 iv.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_MOVE:
            int newX = (int) event.getX();
            int newY = (int) event.getY();
            // 把指定的像素變成透明
            copyBm.setPixel(newX, newY, Color.TRANSPARENT);
            iv.setImageBitmap(copyBm);
            break;
        }
        return true;
    }
});

每次只設置一個像素點太慢,以觸摸的像素為圓心,半徑為5畫圓,圓內的像素全部置為透明

for (int i = -5; i < 6; i++) {
    for (int j = -5; j < 6; j++) {
        if(Math.sqrt(i * i + j * j) <= 5)
            copyBm.setPixel(newX + i, newY + j, Color.TRANSPARENT);
    }
}

5.3 音樂播放器

5.3.1 播放服務

播放音頻的代碼應該運行在服務中,定義一個播放服務MusicService

服務裡定義play、stop、pause、continuePlay等方法

// 播放
private void play() {
    player.reset();
    try {
        player.setDataSource("sdcard/bzj.mp3");
        player.prepare();
    } catch (Exception e) {
        e.printStackTrace();
    } 
    player.start();
}
// 暫停
private void pause() {
    player.pause();
}
// 停止播放
private void stop() {
    player.stop();
}
// 繼續播放
private void continuePlay() {
    player.start();
}
把這幾個方法抽取成一個接口MusicInterface 定義一個中間人類,繼承Binder,實現MusicInterface

先start啟動MusicService,再bind

Intent intent = new Intent(this, MusicService.class);
startService(intent);
bindService(intent, conn, BIND_AUTO_CREATE);

5.3.2 根據播放進度設置進度條

獲取當前的播放時間和當前音頻的最長時間

int currentPosition = player.getCurrentPosition();
int duration = player.getDuration();
播放進度需要不停的獲取,不停的刷新進度條,使用計時器每500毫秒獲取一次播放進度

發消息至Handler,把播放進度放進Message對象中,在Handler中更新SeekBar的進度

Timer timer = new Timer();
timer.schedule(new TimerTask() {

    @Override
    public void run() {
        int currentPosition = player.getCurrentPosition();
        int duration = player.getDuration();
        Message msg = Message.obtain();
        // 把播放進度存入Message中
        Bundle data = new Bundle();
        data.putInt("currentPosition", currentPosition);
        data.putInt("duration", duration);
        msg.setData(data);
        MainActivity.handler.sendMessage(msg);
    }
}, 5, 500);

在Activity中定義Handler

static Handler handler = new Handler(){
    public void handleMessage(android.os.Message msg) {
        // 取出消息攜帶的數據
        Bundle data = msg.getData();
        int currentPosition = data.getInt("currentPosition");
        int duration = data.getInt("duration");

        // 設置播放進度
        sb.setMax(duration);
        sb.setProgress(currentPosition);
    };
};

5.3.3 拖動進度條改變播放進度

設置拖動監聽,拖動後把進度條設置到拖動停止的位置

 // 給sb設置一個拖動偵聽
 sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
    //停止拖動時調用
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        int progress = seekBar.getProgress();
        mi.seekTo(progress);
    }
    // 開始拖動時調用          
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    }
    // 拖動的時候不斷調用            
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
            boolean fromUser) {
    }
}); 

5.4 視頻播放器

SurfaceView

對畫面的實時更新要求較高 雙緩沖技術:內存中有兩個畫布,A畫布顯示至屏幕,B畫布在內存中繪制下一幀畫面,繪制完畢後B顯示至屏幕,A在內存中繼續繪制下一幀畫面

播放視頻也是用MediaPlayer,不過跟音頻不同,要設置顯示在哪個SurfaceView

SurfaceView sv = (SurfaceView) findViewById(R.id.sv);
SurfaceHolder sh = sv.getHolder();

MediaPlayer player = new MediaPlayer();
player.reset();
try {
    player.setDataSource("sdcard/2.3gp");
    player.setDisplay(sh);
    player.prepare();
} catch (Exception e) {
    e.printStackTrace();
}
player.start();
SurfaceView是重量級組件,可見時才會創建

給SurfaceHolder設置CallBack,類似於偵聽,可以知道SurfaceView的狀態

sh.addCallback(new Callback() {
    // SurfaceView銷毀時調用
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }
    // SurfaceView創建時調用
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }
});
SurfaceView一旦不可見,就會被銷毀,一旦可見,就會被創建,銷毀時停止播放,再次創建時再開始播放

5.5 照相機

啟動系統提供的拍照程序

// 隱式啟動系統提供的拍照Activity
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 設置照片的保存路徑
File file = new File(Environment.getExternalStorageDirectory(), "haha.jpg"); 
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); 
startActivityForResult(intent, 0);

啟動系統提供的攝像程序

Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
File file = new File(Environment.getExternalStorageDirectory(), "haha.3gp"); 
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); 
// 設置保存視頻文件的質量
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
startActivityForResult(intent, 0);
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved