본문 바로가기
Android

[Android/Java] 다중이미지 미리보기 구현

by 오늘도 깨달았다 2022. 1. 18.
반응형

다중이미지 미리보기를 구현해봤습니다. 

 

 

카메라, 갤러리 권한을 ted permission을 사용하여 허용시켜줍니다. 

 

build gradle 

implementation "gun0912.ted:tedpermission:2.1.0"

 

Image_activity.class

 

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_user_mypage_fields_add);
    ted();
    
}
void ted() {
        //파일 읽기 권한
        PermissionListener permissionListener = new PermissionListener() {
            @Override
            public void onPermissionGranted() {
                //권한 요청 성공
                //갤러리 동영상 호출
                Intent vod_intent = new Intent(Intent.ACTION_PICK);
                //ACTION_GET_CONTENT을 하게되면, 갤러리뿐 아니라 다른 저장공간에도 접근한다.
                vod_intent.setType(MediaStore.Video.Media.CONTENT_TYPE);

            }

            @Override
            public void onPermissionDenied(ArrayList<String> deniedPermissions) {
                // 권한 요청 실패
                Log.d(TAG, "onPermissionDenied: ");
            }
        };

        TedPermission.with(this)
                .setPermissionListener(permissionListener)
                .setRationaleMessage("설정에서 권한을 허용해주세요.")
                .setDeniedMessage("접근 권한이 필요합니다.")
                .setPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.CAMERA})
                .check();
    }

 

 

먼저 카메라 혹은 갤러리로 이동할 수 있는 버튼과 미리보기 layout을 xml에 정의해줍니다. 

 

activity_image.xml

<?xml version="1.0" encoding="utf-8"?>
    <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"
        android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:orientation="vertical">

        <ImageButton
            android:id="@+id/addImageButton"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginLeft="15dp"
            android:backgroundTint="@color/white"
            app:srcCompat="@drawable/ic_image__9_" />

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:id="@+id/layout"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:layout_marginTop="15dp"
                android:orientation="vertical" />
        </ScrollView>
    </LinearLayout>

</LinearLayout>

 

카메라, 갤러리로 이동할 버튼의 뷰 매칭 및 갤러리 화면에서 받을 result 분기점을 정의합니다.

 

 

 

Image_Activity.java

//카메라, 혹은 갤러리로 이동할 버튼
ImageButton addImageButton;
//앨범에서 가져온 파일들 (다중선택 가능)
private static final int PICK_FROM_ALBUM = 1;
//카메라 캡처로 가져온 사진
public static final int REQUEST_IMAGE_CAPTURE = 3;

//카메라 혹은 앨범으로 이동할 dialog 정의
public ProgressDialog pDialog;

//미리보기 이미지를 담을 layout
private LinearLayout layout;

//파일의 실제 경로를 담을 arraylist
private ArrayList<String> filePaths = new ArrayList<String>();

 

버튼과 view를 연결해줍니다. 

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_mypage_fields_add);
        ted();
		
        
        //미리보기 이미지를 담을 뷰
        layout = findViewById(R.id.layout);
        
        //미리보기 이미지 추가할 버튼
	addImageButton = findViewById(R.id.addImageButton);
        
        
    }

 

코드 가독성을 위해 카메라나 갤러리로 이동하는 메소드를 따로 빼줍니다.

 

//이미지 관련 작업내용들
addImageButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {


        photoDialogList();


    }
});

 

앨범선택과 사진촬영 중 원하는 부분을 선택하도록 Alertdialog를 생성해줍니다.

//사진 선택 다이얼로그
void photoDialogList() {
    final List<String> ListItems = new ArrayList<>();
    ListItems.add("앨범 선택");
    ListItems.add("사진 촬영");

    final CharSequence[] items = ListItems.toArray(new String[ListItems.size()]);

	//alertdialog 객체 생성
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setItems(items, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int pos) {
            String selectedText = items[pos].toString();

            if (selectedText.contains("앨범 선택")) {
                goToAlbum();
            } else {
                takephoto();
            }


        }
    });
    builder.show();
}

 

goToAlbum()

//앨범으로
private void goToAlbum() {

    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType(MediaStore.Images.Media.CONTENT_TYPE);
    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
    
    //갤러리의 이미지만 확인하겠다.
    intent.setType("image/*");


	//결과값은 PICK_FROM_ALBUM 에서 받겠다.
    startActivityForResult(intent, PICK_FROM_ALBUM);
}

 

takephoto()

//카메라로 이동
public void takephoto() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {

        File photoFile = null;

        try {
        //임시파일 생성
            File tempDir = getCacheDir();

            String timeStamp = new SimpleDateFormat("yyyyMMdd", Locale.KOREA).format(new Date());
            String imageFileName = "Capture_" + timeStamp + "_";
            File tempImage = File.createTempFile(
                    imageFileName,
                    ".jpg",
                    tempDir
            );

			//임시파일의 절대경로
            mCurrentPhotoPath = tempImage.getAbsolutePath();

            photoFile = tempImage;


        } catch (Exception e) {

            Log.w(TAG, "파일 생성 에러!", e);

        }


        Log.e(TAG, photoFile + "포토파일");

        if (photoFile != null) {
            Uri photoURI = FileProvider.getUriForFile(this,
                    getPackageName() + ".fileprovider",
                    photoFile);

            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);


			//결과값을 REQUEST_IMAGE_CAPTURE 에서 받겠다.
            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
        }
    }

}

 

앨범이나, 카메라 이동 후 가져온 이미지들 처리할 onActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);

    switch (requestCode) {
    
    //카메라
        case REQUEST_IMAGE_CAPTURE:
            if (resultCode == RESULT_OK) {

			//받아온 사진의 경로를 파일로 생성한다.
                File file = new File(mCurrentPhotoPath);

			//file의 uri 경로를 가져온다.
                Uri imageUri = Uri.fromFile(file);
                
			//미리보기에 삽입
                makeImageView(imageUri);

            }
            break;
	//앨범
        case PICK_FROM_ALBUM:
            if (resultCode == RESULT_OK) {

			//가져온 다수의 사진을 이미지 미리보기에 넣는다.
                ClipData clipData = intent.getClipData();
                if (clipData != null) {
                    for (int i = 0; i < clipData.getItemCount(); i++) {
                        if (i < clipData.getItemCount()) {
                            Uri imageUri = clipData.getItemAt(i).getUri();
                            makeImageView(imageUri);
                        }
                    }
                }
            }
            break;


    }


}

 

makeImageView() --> 이미지 미리보기 생성

 

 


private void makeImageView(Uri uri) {
    //이미지 삭제 버튼을 넣어주기 위한 프레임 레이아웃인데 이미지를 프레임에 넣고, 삭제 버튼이미지도 프레임에 넣어준다
    FrameLayout frameLayout = new FrameLayout(this);
    //삭제버튼 이미지
    ImageView deleteView = new ImageView(this);
    ImageView imageView = new ImageView(this);
    //파일의 절대 경로를 알아온다
    String absolutePath = getRealPathFromURI(getApplicationContext(), uri);

    filePaths.add(absolutePath);
    if (frameLayout != null) {
        frameLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                layout.removeView(frameLayout);
                //위에서 만들 file을 사용하여 데이터를 지워준다.
                System.out.println("지워지는 데이터 : " + uri);
                System.out.println("리스트의 데이터 : " + filePaths);
                //리스트에서도 같이 지워준다.
                filePaths.remove(absolutePath);

            }
        });
    }
    //딜리트이미지 세팅
    deleteView.setImageResource(R.drawable.remove);
    //삭제 이미지뷰의 크기 조절
    LinearLayout.LayoutParams deleteImgParams = new LinearLayout.LayoutParams(60, 60);
    //삭제 이미지뷰의 위치 조절
    deleteImgParams.setMargins(940, 0, 0, 0);
    deleteView.setLayoutParams(deleteImgParams);


    System.out.println("이건 이미지!");
    //글라이드로 이미지 크기 조정
    Glide.with(imageView)
            .load(uri)
            .override(MATCH_PARENT, MATCH_PARENT)
            .into(imageView);

    //이미지뷰의 크기 조절
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(1000, 500);

    params.topMargin = 15;
    params.leftMargin = 15;
    imageView.setLayoutParams(params);

    imageView.setScaleType(ImageView.ScaleType.FIT_XY);

    frameLayout.setLayoutParams(params);
    frameLayout.addView(imageView);
    frameLayout.addView(deleteView);


    layout.addView(frameLayout);
    System.out.println("현재 이미지 리스트의 데이터들 : " + filePaths);
}

 

 

혹시라도 본인의 서버에 업로드하기위해 이미지의 uri 경로 말고 절대경로가 필요할 수 있으니 절대경로를 구하는 메소드도 함께 업로드하겠습니다.

 

//파일의 절대경로를 알아오는 메서드
public static String getRealPathFromURI(final Context context, final Uri uri) {

    // DocumentProvider
    if (DocumentsContract.isDocumentUri(context, uri)) {

        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];
            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/"
                        + split[1];
            } else {
                String SDcardpath = getRemovableSDCardPath(context).split("/Android")[0];
                return SDcardpath + "/" + split[1];
            }
        }


        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {
            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"),
                    Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }

        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else {
                Toast.makeText(context.getApplicationContext(), "이미지가 아닙니다.", Toast.LENGTH_SHORT).show();
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[]{split[1]};

            return getDataColumn(context, contentUri, selection,
                    selectionArgs);
        }

    } else if ("content".equalsIgnoreCase(uri.getScheme())) {
        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();
        return getDataColumn(context, uri, null, null);
    } else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }
    return null;
}

public static String getDataColumn(Context context, Uri uri,
                                   String selection, String[] selectionArgs) {

    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {column};

    try {
        cursor = context.getContentResolver().query(uri, projection,
                selection, selectionArgs, null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}


public static String getRemovableSDCardPath(Context context) {
    File[] storages = ContextCompat.getExternalFilesDirs(context, null);
    if (storages.length > 1 && storages[0] != null && storages[1] != null)
        return storages[1].toString();
    else
        return "";
}

public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri
            .getAuthority());
}

public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri
            .getAuthority());
}

public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri
            .getAuthority());
}


public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri
            .getAuthority());
}

 

 

 

 

궁금한점이나 안되는 부분은 댓글 달아주세요.

반응형

댓글