欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)圖片拼接并保存至相冊(cè)

 更新時(shí)間:2025年06月10日 08:21:33   作者:計(jì)蒙不吃魚(yú)  
在Android應(yīng)用中實(shí)現(xiàn)圖片拼接功能并保存到相冊(cè)是一個(gè)常見(jiàn)的需求,本文將介紹如何實(shí)現(xiàn)一個(gè)完整的圖片拼接應(yīng)用,包括圖片選擇,拼接和保存功能

前言

好久沒(méi)有寫(xiě)Android系列的文章了,最近有小伙伴問(wèn)到了Android圖片拼接的問(wèn)題,寫(xiě)一篇相關(guān)的博客。

在Android應(yīng)用中實(shí)現(xiàn)圖片拼接功能并保存到相冊(cè)是一個(gè)常見(jiàn)的需求,比如制作全景圖、拼圖應(yīng)用或照片編輯工具。本文將介紹如何實(shí)現(xiàn)一個(gè)完整的圖片拼接應(yīng)用,包括圖片選擇、拼接和保存功能。

實(shí)現(xiàn)功能

  • 檢查并請(qǐng)求必要的存儲(chǔ)權(quán)限
  • 允許用戶從相冊(cè)選擇一張或多張圖片
  • 異步加載選中的圖片
  • 使用ImageStitcher類拼接圖片
  • 將拼接后的圖片保存到相冊(cè)
  • 在整個(gè)過(guò)程中顯示適當(dāng)?shù)倪M(jìn)度指示和操作反饋

類定義和成員變量

其中包括圖片選擇請(qǐng)求碼,讀取權(quán)限請(qǐng)求碼, 寫(xiě)入權(quán)限請(qǐng)求碼,保存目錄名稱,以及相關(guān)控件。

public class MainActivity extends AppCompatActivity {
    private static final int PICK_IMAGE_REQUEST = 1;  // 圖片選擇請(qǐng)求碼
    private static final int REQUEST_PERMISSION = 2;  // 讀取權(quán)限請(qǐng)求碼
    private static final int REQUEST_WRITE_PERMISSION = 3;  // 寫(xiě)入權(quán)限請(qǐng)求碼
    private static final String SAVE_DIRECTORY = "ImageStitcher";  // 保存目錄名稱
    
    private List<Bitmap> selectedImages = new ArrayList<>();  // 存儲(chǔ)選擇的圖片
    private ImageView resultView;  // 顯示拼接結(jié)果的ImageView
    private ProgressBar progressBar;  // 進(jìn)度條
    private Button selectBtn, stitchBtn, saveBtn;  // 按鈕控件

onCreate方法

初始化控件以及設(shè)置監(jiān)聽(tīng)

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);  // 設(shè)置布局文件

    // 初始化視圖控件
    resultView = findViewById(R.id.jm_result_image);
    progressBar = findViewById(R.id.jm_progress_bar);
    selectBtn = findViewById(R.id.jm_select_btn);
    stitchBtn = findViewById(R.id.jm_stitch_btn);
    saveBtn = findViewById(R.id.jm_save_btn);
    saveBtn.setVisibility(View.GONE);  // 初始時(shí)隱藏保存按鈕

    // 設(shè)置按鈕點(diǎn)擊監(jiān)聽(tīng)器
    selectBtn.setOnClickListener(v -> checkPermissionAndOpenChooser());
    stitchBtn.setOnClickListener(v -> stitchImagesAsync());
}

權(quán)限檢查和圖片選擇

不動(dòng)態(tài)申請(qǐng)權(quán)限小心報(bào)錯(cuò):has no access to content 需在AndroidManifest.xml聲明READ_EXTERNAL_STORAGE權(quán)限,Android Q及以上版本必須使用MediaStore API訪問(wèn)公共目錄文件。

private void checkPermissionAndOpenChooser() {
    // 檢查是否有讀取外部存儲(chǔ)權(quán)限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
            == PackageManager.PERMISSION_GRANTED) {
        openImageChooser();  // 有權(quán)限則直接打開(kāi)圖片選擇器
    } else {
        // 沒(méi)有權(quán)限則請(qǐng)求權(quán)限
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                REQUEST_PERMISSION);
    }
}

private void openImageChooser() {
    // 創(chuàng)建選擇圖片的Intent
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("image/*");  // 設(shè)置類型為圖片
    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);  // 允許多選
    startActivityForResult(Intent.createChooser(intent, "選擇圖片"), PICK_IMAGE_REQUEST);
}

// 權(quán)限請(qǐng)求結(jié)果回調(diào)
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_PERMISSION && grantResults.length > 0
            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        openImageChooser();  // 權(quán)限被授予后打開(kāi)圖片選擇器
    }
}

處理選擇的圖片

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
        handleSelectedImages(data);  // 處理選擇的圖片
    }
}

private void handleSelectedImages(Intent data) {
    progressBar.setVisibility(View.VISIBLE);  // 顯示進(jìn)度條
    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.execute(() -> {
        try {
            if (data.getClipData() != null) {
                processMultipleImages(data.getClipData());  // 處理多張圖片
            } else if (data.getData() != null) {
                processSingleImage(data.getData());  // 處理單張圖片
            }
        } finally {
            runOnUiThread(() -> progressBar.setVisibility(View.GONE));  // 隱藏進(jìn)度條
        }
    });
}

private void processMultipleImages(ClipData clipData) {
    for (int i = 0; i < clipData.getItemCount(); i++) {
        loadAndAddImage(clipData.getItemAt(i).getUri());  // 加載并添加每張圖片
    }
}

private void processSingleImage(Uri uri) {
    loadAndAddImage(uri);  // 加載并添加單張圖片
}

private void loadAndAddImage(Uri uri) {
    try (InputStream is = getContentResolver().openInputStream(uri)) {
        Bitmap bitmap = BitmapFactory.decodeStream(is);  // 從URI加載圖片
        runOnUiThread(() -> {
            selectedImages.add(bitmap);  // 添加到圖片列表
            Toast.makeText(this, "成功加載圖片", Toast.LENGTH_SHORT).show();
        });
    } catch (Exception e) {
        runOnUiThread(() ->
                Toast.makeText(this, "加載失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show());
    }
}

圖片拼接功能

private void stitchImagesAsync() {
    if (selectedImages.isEmpty()) return;  // 如果沒(méi)有選擇圖片則返回
    
    saveBtn.setVisibility(View.VISIBLE);  // 顯示保存按鈕
    progressBar.setVisibility(View.VISIBLE);  // 顯示進(jìn)度條
    
    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.execute(() -> {
        // 調(diào)用ImageStitcher類拼接圖片
        Bitmap stitched = ImageStitcher.stitchImages(
                selectedImages.toArray(new Bitmap[0]), 0);
        
        runOnUiThread(() -> {
            resultView.setImageBitmap(stitched);  // 顯示拼接結(jié)果
            progressBar.setVisibility(View.GONE);  // 隱藏進(jìn)度條
            saveBtn.setVisibility(View.VISIBLE);  // 確保保存按鈕可見(jiàn)
            // 設(shè)置保存按鈕點(diǎn)擊監(jiān)聽(tīng)器
            saveBtn.setOnClickListener(v -> saveImageToGallery(stitched));
        });
    });
}

圖片保存功能

private void saveImageToGallery(Bitmap bitmap) {
    // 檢查是否有寫(xiě)入外部存儲(chǔ)權(quán)限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        // 沒(méi)有權(quán)限則請(qǐng)求權(quán)限
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_WRITE_PERMISSION);
        return;
    }

    // 在新線程中執(zhí)行保存操作
    new Thread(() -> {
        String fileName = "stitched_" + System.currentTimeMillis() + ".jpg";
        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");

        // 對(duì)于Android Q及以上版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            values.put(MediaStore.Images.Media.RELATIVE_PATH, 
                     Environment.DIRECTORY_PICTURES + File.separator + SAVE_DIRECTORY);
            values.put(MediaStore.Images.Media.IS_PENDING, 1);
        }

        try {
            // 插入媒體庫(kù)記錄
            Uri uri = getContentResolver().insert(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

            try (OutputStream os = getContentResolver().openOutputStream(uri)) {
                // 壓縮并寫(xiě)入圖片數(shù)據(jù)
                bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os);
                
                // 對(duì)于Android Q及以上版本,更新IS_PENDING標(biāo)志
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    values.put(MediaStore.Images.Media.IS_PENDING, 0);
                    getContentResolver().update(uri, values, null, null);
                }
                
                // 顯示保存成功提示
                runOnUiThread(() ->
                        Toast.makeText(this, "圖片已保存至相冊(cè)", Toast.LENGTH_SHORT).show());
            }
        } catch (Exception e) {
            // 顯示保存失敗提示
            runOnUiThread(() ->
                    Toast.makeText(this, "保存失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show());
        }
    }).start();
}

使用ImageStitcher類拼接圖片

代碼解釋:ImageStitcher.java

這是一個(gè)用于拼接多張圖片的工具類,提供了將多張圖片橫向或縱向拼接成一張大圖的功能。下面是對(duì)代碼的詳細(xì)解釋:

類定義和方法

public class ImageStitcher {
    public static Bitmap stitchImages(Bitmap[] images, int direction) {
        // 檢查輸入?yún)?shù)是否有效
        if (images == null || images.length == 0) return null;

計(jì)算拼接后圖片的尺寸

        int width = images[0].getWidth();
        int height = images[0].getHeight();

        // 計(jì)算拼接后圖片的總尺寸
        if (direction == 0) { // 橫向拼接
            for (int i = 1; i < images.length; i++) {
                width += images[i].getWidth();  // 累加寬度
                height = Math.max(height, images[i].getHeight());  // 取最大高度
            }
        } else { // 縱向拼接
            for (int i = 1; i < images.length; i++) {
                height += images[i].getHeight();  // 累加高度
                width = Math.max(width, images[i].getWidth());  // 取最大寬度
            }
        }

計(jì)算邏輯

橫向拼接:總寬度為所有圖片寬度之和,高度為所有圖片中的最大高度

縱向拼接:總高度為所有圖片高度之和,寬度為所有圖片中的最大寬度

創(chuàng)建并繪制拼接后的圖片

        // 創(chuàng)建拼接后的Bitmap
        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);

        // 繪制圖片
        int currentPos = 0;
        for (Bitmap image : images) {
            if (direction == 0) { // 橫向拼接
                canvas.drawBitmap(image, currentPos, 0, null);  // 在當(dāng)前位置繪制圖片
                currentPos += image.getWidth();  // 更新橫向位置
            } else { // 縱向拼接
                canvas.drawBitmap(image, 0, currentPos, null);  // 在當(dāng)前位置繪制圖片
                currentPos += image.getHeight();  // 更新縱向位置
            }
        }

        return result;  // 返回拼接后的圖片
    }
}

繪制過(guò)程

  • 創(chuàng)建一個(gè)新的空白Bitmap,大小為之前計(jì)算的總尺寸
  • 使用Canvas在這個(gè)Bitmap上繪制所有輸入圖片
  • 根據(jù)拼接方向,依次將每張圖片繪制到正確的位置
  • 更新當(dāng)前位置指針(currentPos),以便下一張圖片繪制在正確的位置

注意事項(xiàng)

  • 所有輸入圖片應(yīng)為非空且尺寸相同(代碼中未做嚴(yán)格檢查)
  • 拼接方向通過(guò)簡(jiǎn)單的int值判斷(0為橫向,非0為縱向)
  • 使用了ARGB_8888配置創(chuàng)建Bitmap,保證圖片質(zhì)量
  • 這是一個(gè)基礎(chǔ)實(shí)現(xiàn),沒(méi)有處理圖片尺寸不一致時(shí)的縮放或裁剪

效果圖

源碼

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.ClipData;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class MainActivity extends AppCompatActivity {
    private static final int PICK_IMAGE_REQUEST = 1;
    private static final int REQUEST_PERMISSION = 2;
    private List<Bitmap> selectedImages = new ArrayList<>();
    private ImageView resultView;
    private ProgressBar progressBar;
    private static final int REQUEST_WRITE_PERMISSION = 3;
    private static final String SAVE_DIRECTORY = "JmImgStitcher";
    private Button selectBtn,stitchBtn,saveBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        resultView = findViewById(R.id.jm_result_image);
        progressBar = findViewById(R.id.jm_progress_bar);
        selectBtn = findViewById(R.id.jm_select_btn);
        stitchBtn = findViewById(R.id.jm_stitch_btn);
        // 初始化保存按鈕
        saveBtn = findViewById(R.id.jm_save_btn);
        saveBtn.setVisibility(View.GONE);

        selectBtn.setOnClickListener(v -> checkPermissionAndOpenChooser());
        stitchBtn.setOnClickListener(v -> stitchImagesAsync());
    }

    private void checkPermissionAndOpenChooser() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            openImageChooser();
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    REQUEST_PERMISSION);
        }
    }

    private void openImageChooser() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        startActivityForResult(Intent.createChooser(intent, "選擇圖片"), PICK_IMAGE_REQUEST);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION && grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            openImageChooser();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
            handleSelectedImages(data);
        }
    }

    private void handleSelectedImages(Intent data) {
        progressBar.setVisibility(View.VISIBLE);
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> {
            try {
                if (data.getClipData() != null) {
                    processMultipleImages(data.getClipData());
                } else if (data.getData() != null) {
                    processSingleImage(data.getData());
                }
            } finally {
                runOnUiThread(() -> progressBar.setVisibility(View.GONE));
            }
        });
    }

    private void processMultipleImages(ClipData clipData) {
        for (int i = 0; i < clipData.getItemCount(); i++) {
            loadAndAddImage(clipData.getItemAt(i).getUri());
        }
    }

    private void processSingleImage(Uri uri) {
        loadAndAddImage(uri);
    }

    private void loadAndAddImage(Uri uri) {
        try (InputStream is = getContentResolver().openInputStream(uri)) {
            Bitmap bitmap = BitmapFactory.decodeStream(is);
            runOnUiThread(() -> {
                selectedImages.add(bitmap);
                Toast.makeText(this, "成功加載圖片", Toast.LENGTH_SHORT).show();
            });
        } catch (Exception e) {
            runOnUiThread(() ->
                    Toast.makeText(this, "加載失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show());
        }
    }

    // 修改stitchImagesAsync方法
    private void stitchImagesAsync() {
        if (selectedImages.isEmpty()) return;
        saveBtn.setVisibility(View.VISIBLE);
        progressBar.setVisibility(View.VISIBLE);
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> {
            Bitmap stitched = ImageStitcher.stitchImages(
                    selectedImages.toArray(new Bitmap[0]), 0);
            runOnUiThread(() -> {
                resultView.setImageBitmap(stitched);
                progressBar.setVisibility(View.GONE);
                //設(shè)置出現(xiàn)
                saveBtn.setVisibility(View.VISIBLE);
                saveBtn.setOnClickListener(v -> saveImageToGallery(stitched));
            });
        });

    }

    private void saveImageToGallery(Bitmap bitmap) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    REQUEST_WRITE_PERMISSION);
            return;
        }

        new Thread(() -> {
            String fileName = "stitched_" + System.currentTimeMillis() + ".jpg";
            ContentValues values = new ContentValues();
            values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
            values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + SAVE_DIRECTORY);
                values.put(MediaStore.Images.Media.IS_PENDING, 1);
            }

            try {
                Uri uri = getContentResolver().insert(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

                try (OutputStream os = getContentResolver().openOutputStream(uri)) {
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        values.put(MediaStore.Images.Media.IS_PENDING, 0);
                        getContentResolver().update(uri, values, null, null);
                    }
                    runOnUiThread(() ->
                            Toast.makeText(this, "圖片已保存至相冊(cè)", Toast.LENGTH_SHORT).show());
                }
            } catch (Exception e) {
                runOnUiThread(() ->
                        Toast.makeText(this, "保存失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show());
            }
        }).start();
    }

}

ImageStitcher.java

import android.graphics.Bitmap;
import android.graphics.Canvas;

public class ImageStitcher {
    public static Bitmap stitchImages(Bitmap[] images, int direction) {
        if (images == null || images.length == 0) return null;

        int width = images[0].getWidth();
        int height = images[0].getHeight();

        // 計(jì)算拼接后圖片的總尺寸
        if (direction == 0) { // 橫向拼接
            for (int i = 1; i < images.length; i++) {
                width += images[i].getWidth();
                height = Math.max(height, images[i].getHeight());
            }
        } else { // 縱向拼接
            for (int i = 1; i < images.length; i++) {
                height += images[i].getHeight();
                width = Math.max(width, images[i].getWidth());
            }
        }

        // 創(chuàng)建拼接后的Bitmap
        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);

        // 繪制圖片
        int currentPos = 0;
        for (Bitmap image : images) {
            if (direction == 0) { // 橫向拼接
                canvas.drawBitmap(image, currentPos, 0, null);
                currentPos += image.getWidth();
            } else { // 縱向拼接
                canvas.drawBitmap(image, 0, currentPos, null);
                currentPos += image.getHeight();
            }
        }

        return result;
    }
}

AndroidManifest權(quán)限申明

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- Android 10+ 需要添加 -->
    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"
        android:maxSdkVersion="29" />

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ProgressBar
        android:id="@+id/jm_progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="gone"/>
    <Button
        android:id="@+id/jm_select_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="選擇要拼接的圖片"/>

    <Button
        android:id="@+id/jm_stitch_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="開(kāi)始拼接圖片"/>
    <Button
        android:id="@+id/jm_save_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="保存圖片"
        android:visibility="gone"/>
    <ImageView
        android:id="@+id/jm_result_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerInside"/>
</LinearLayout>

以上就是Android實(shí)現(xiàn)圖片拼接并保存至相冊(cè)的詳細(xì)內(nèi)容,更多關(guān)于Android圖片拼接的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于Android studio3.6的JNI教程之helloworld思路詳解

    基于Android studio3.6的JNI教程之helloworld思路詳解

    這篇文章主要介紹了基于Android studio3.6的JNI教程之helloworld,本文通過(guò)圖文實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Android中使用TextToSpeech的方法

    Android中使用TextToSpeech的方法

    這篇文章主要介紹了Android中TextToSpeech的使用,通過(guò)初始化語(yǔ)音,這是一個(gè)異步操作,初始化完成后調(diào)用oninitListener,具體實(shí)例代碼跟隨小編一起看看吧
    2021-09-09
  • Flutter自動(dòng)路由插件auto_route使用詳解

    Flutter自動(dòng)路由插件auto_route使用詳解

    這篇文章主要為大家介紹了Flutter自動(dòng)路由插件auto_route的基本使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Flutter 如何正確顯示SnackBar

    Flutter 如何正確顯示SnackBar

    Snackbar是Android支持庫(kù)中用于顯示簡(jiǎn)單消息并且提供和用戶的一個(gè)簡(jiǎn)單操作的一種彈出式提醒。當(dāng)使用Snackbar時(shí),提示會(huì)出現(xiàn)在消息最底部,通常含有一段信息和一個(gè)可點(diǎn)擊的按鈕。本文主要介紹了Flutter 如何正確顯示 SnackBar
    2021-05-05
  • GreenDao 3.2.0 的基本使用

    GreenDao 3.2.0 的基本使用

    本文主要對(duì)GreenDao 3.2.0 的基本使用進(jìn)行詳細(xì)介紹。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-01-01
  • Android仿iPhone日期時(shí)間選擇器詳解

    Android仿iPhone日期時(shí)間選擇器詳解

    這篇文章主要為大家詳細(xì)介紹了Android仿iPhone日期時(shí)間選擇器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Android多媒體之VideoView視頻播放器

    Android多媒體之VideoView視頻播放器

    這篇文章主要為大家詳細(xì)介紹了Android多媒體之VideoView視頻播放器的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • Android Data Binding數(shù)據(jù)綁定詳解

    Android Data Binding數(shù)據(jù)綁定詳解

    本文主要介紹Android Data Binding數(shù)據(jù)綁定的知識(shí),這里整理了詳細(xì)的資料及簡(jiǎn)單示例代碼幫助大家學(xué)習(xí)理解此部分知識(shí),有需要的小伙伴可以參考下
    2016-09-09
  • Android實(shí)現(xiàn)仿微軟系統(tǒng)加載動(dòng)畫(huà)效果

    Android實(shí)現(xiàn)仿微軟系統(tǒng)加載動(dòng)畫(huà)效果

    這篇文章主要介紹了Android實(shí)現(xiàn)仿微軟系統(tǒng)加載動(dòng)畫(huà)效果的方法,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下
    2021-04-04
  • android自定義加減按鈕

    android自定義加減按鈕

    這篇文章主要為大家詳細(xì)介紹了android自定義加減按鈕,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03

最新評(píng)論