最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

好久沒有寫Android系列的文章了,最近有小伙伴問到了Android圖片拼接的問題,寫一篇相關的博客。

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

實現(xiàn)功能

  • 檢查并請求必要的存儲權限
  • 允許用戶從相冊選擇一張或多張圖片
  • 異步加載選中的圖片
  • 使用ImageStitcher類拼接圖片
  • 將拼接后的圖片保存到相冊
  • 在整個過程中顯示適當?shù)倪M度指示和操作反饋

類定義和成員變量

其中包括圖片選擇請求碼,讀取權限請求碼, 寫入權限請求碼,保存目錄名稱,以及相關控件。

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

onCreate方法

初始化控件以及設置監(jiān)聽

@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);  // 初始時隱藏保存按鈕

    // 設置按鈕點擊監(jiān)聽器
    selectBtn.setOnClickListener(v -> checkPermissionAndOpenChooser());
    stitchBtn.setOnClickListener(v -> stitchImagesAsync());
}

權限檢查和圖片選擇

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

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() {
    // 創(chuàng)建選擇圖片的Intent
    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);
}

// 權限請求結(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();  // 權限被授予后打開圖片選擇器
    }
}

處理選擇的圖片

@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);  // 從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;  // 如果沒有選擇圖片則返回
    
    saveBtn.setVisibility(View.VISIBLE);  // 顯示保存按鈕
    progressBar.setVisibility(View.VISIBLE);  // 顯示進度條
    
    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);  // 隱藏進度條
            saveBtn.setVisibility(View.VISIBLE);  // 確保保存按鈕可見
            // 設置保存按鈕點擊監(jiān)聽器
            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;
    }

    // 在新線程中執(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");

        // 對于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 {
            // 插入媒體庫記錄
            Uri uri = getContentResolver().insert(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

            try (OutputStream os = getContentResolver().openOutputStream(uri)) {
                // 壓縮并寫入圖片數(shù)據(jù)
                bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os);
                
                // 對于Android Q及以上版本,更新IS_PENDING標志
                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, "圖片已保存至相冊", Toast.LENGTH_SHORT).show());
            }
        } catch (Exception e) {
            // 顯示保存失敗提示
            runOnUiThread(() ->
                    Toast.makeText(this, "保存失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show());
        }
    }).start();
}

使用ImageStitcher類拼接圖片

代碼解釋:ImageStitcher.java

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

類定義和方法

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

計算拼接后圖片的尺寸

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

        // 計算拼接后圖片的總尺寸
        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)建并繪制拼接后的圖片

        // 創(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;  // 返回拼接后的圖片
    }
}

繪制過程

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

注意事項

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

效果圖

源碼

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);
                //設置出現(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, "圖片已保存至相冊", 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();

        // 計算拼接后圖片的總尺寸
        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權限申明

    <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="開始拼接圖片"/>
    <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實現(xiàn)圖片拼接并保存至相冊的詳細內(nèi)容,更多關于Android圖片拼接的資料請關注腳本之家其它相關文章!

相關文章

  • java  深入理解內(nèi)存映射文件原理

    java 深入理解內(nèi)存映射文件原理

    這篇文章主要介紹了java 深入理解內(nèi)存映射文件原理的相關資料,虛擬內(nèi)存與內(nèi)存映射文件的區(qū)別與聯(lián)系,內(nèi)存映射文件的原理和效率,需要的朋友可以參考下
    2016-11-11
  • Android實現(xiàn)圖片疊加效果的兩種方法

    Android實現(xiàn)圖片疊加效果的兩種方法

    這篇文章主要介紹了Android實現(xiàn)圖片疊加效果的兩種方法,結(jié)合實例形式分析了Android實現(xiàn)圖片疊加效果的兩種操作方法與相關注意事項,需要的朋友可以參考下
    2016-08-08
  • 如何從UA分辨出Android設備類型

    如何從UA分辨出Android設備類型

    本文主要介紹如何從UA分辨出Android設備類型,這里整理了相關資料,來講解分辨Android設備類型,有興趣的小伙伴可以參考下
    2016-08-08
  • Android中的Bitmap緩存池使用詳解

    Android中的Bitmap緩存池使用詳解

    這篇文章主要介紹了Android中的Bitmap緩存池使用詳解,本文主要目的是講解如何使用緩存來提高UI的載入輸入和滑動的流暢性,需要的朋友可以參考下
    2015-01-01
  • Android屏幕旋轉(zhuǎn)之橫屏豎屏切換的實現(xiàn)

    Android屏幕旋轉(zhuǎn)之橫屏豎屏切換的實現(xiàn)

    這篇文章主要介紹了Android屏幕旋轉(zhuǎn)之橫屏豎屏切換的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-10-10
  • Android中AsyncTask的用法實例分享

    Android中AsyncTask的用法實例分享

    AsyncTask的特點是任務在主線程之外運行,而回調(diào)方法是在主線程中執(zhí)行, 這就有效地避免了使用Handler帶來的麻煩
    2014-02-02
  • Android基于OpenCV實現(xiàn)QR二維碼檢測

    Android基于OpenCV實現(xiàn)QR二維碼檢測

    QR碼比普通一維條碼具有快速讀取和更大的存儲資料容量,也無需要像一維條碼般在掃描時需要直線對準掃描儀。因此其應用范圍已經(jīng)擴展到包括產(chǎn)品跟蹤,物品識別,文檔管理,庫存營銷等方面。本文講解Android基于OpenCV實現(xiàn)QR二維碼檢測的步驟
    2021-06-06
  • Android Canvas之drawBitmap方法案例詳解

    Android Canvas之drawBitmap方法案例詳解

    這篇文章主要介紹了Android Canvas之drawBitmap方法案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Android實現(xiàn)遮罩層(蒙板)效果

    Android實現(xiàn)遮罩層(蒙板)效果

    這篇文章主要為大家詳細介紹了Android實現(xiàn)遮罩層效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Android Studio調(diào)試功能使用匯總

    Android Studio調(diào)試功能使用匯總

    這篇文章主要為大家詳細介紹了Android Studio調(diào)試功能使用方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05

最新評論

新源县| 新龙县| 伊宁市| 莱阳市| 莱阳市| 永平县| 呼和浩特市| 乌海市| 青河县| 封开县| 高安市| 静海县| 武川县| 达拉特旗| 德安县| 上思县| 中江县| 龙胜| 阳西县| 安福县| 大埔区| 上思县| 临西县| 沈丘县| 邵阳县| 上栗县| 绍兴县| 泽库县| 隆昌县| 鸡西市| 井陉县| 和林格尔县| 楚雄市| 清河县| 江北区| 嘉义县| 高唐县| 江口县| 乌审旗| 石嘴山市| 崇义县|