📌  相关文章
📜  如何在Android中构建照片查看应用程序?

📅  最后修改于: 2021-05-13 15:57:25             🧑  作者: Mango

Gallery应用程序是预装在许多android设备上的最常用的应用程序之一,并且Google Play中提供了几种不同的应用程序来查看设备中存在的媒体文件。在本文中,我们将简单地创建一个Gallery应用程序,在其中我们可以查看存储在设备上的所有照片。除此之外,我们还可以在我们的应用程序中查看单个照片。

我们将在本文中构建什么?

我们将构建一个简单的应用程序,在该应用程序中,我们将简单地以网格格式显示照片列表,并在单击照片时可以查看该照片并可以放大该照片以正确查看它。下面是vide0,我们将在其中看到我们将要构建的内容。

分步实施

步骤1:创建一个新项目

要在Android Studio中创建新项目,请参阅如何在Android Studio中创建/启动新项目。请注意,选择Java作为编程语言。

步骤2:在build.gradle文件中添加依赖项

导航到应用程序> Gradle脚本> build.gradle(:app)并向其添加以下依赖项。我们正在使用Picasso从ImageView中的路径加载图像。

现在同步您的项目,我们将朝着在AndroidManifest.xml文件中添加权限的方向进行。

步骤3:在我们的AndroidManifest.xml文件中添加权限

导航至应用程序> AndroidManifest.xml文件,然后向其添加以下权限。

XML


XML
android:hardwareAccelerated="false"
android:largeHeap="true"


XML


  
    
    
  


XML


  
    
    
  


Java
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
  
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
  
import com.squareup.picasso.Picasso;
  
import java.io.File;
import java.util.ArrayList;
  
public class RecyclerViewAdapter extends RecyclerView.Adapter {
      
    // creating a variable for our context and array list.
    private final Context context;
    private final ArrayList imagePathArrayList;
  
    // on below line we have created a constructor.
    public RecyclerViewAdapter(Context context, ArrayList imagePathArrayList) {
        this.context = context;
        this.imagePathArrayList = imagePathArrayList;
    }
  
    @NonNull
    @Override
    public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // Inflate Layout in this method whch we have created.
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false);
        return new RecyclerViewHolder(view);
    }
  
    @Override
    public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
          
        // on below line we are getting th file from the
        // path which we have stored in our list.
        File imgFile = new File(imagePathArrayList.get(position));
          
        // on below line we are checking if tje file exists or not.
        if (imgFile.exists()) {
              
            // if the file exists then we are displaying that file in our image view using picasso library.
            Picasso.get().load(imgFile).placeholder(R.drawable.ic_launcher_background).into(holder.imageIV);
              
            // on below line we are adding click listener to our item of recycler view.
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                      
                    // inside on click listner we are creating a new intent
                    Intent i = new Intent(context, ImageDetailActivity.class);
                      
                    // on below line we are passing the image path to our new activity.
                    i.putExtra("imgPath", imagePathArrayList.get(position));
                      
                    // at last we are starting our activity.
                    context.startActivity(i);
                }
            });
        }
    }
  
    @Override
    public int getItemCount() {
        // this method returns 
        // the size of recyclerview
        return imagePathArrayList.size();
    }
  
    // View Holder Class to handle Recycler View.
    public static class RecyclerViewHolder extends RecyclerView.ViewHolder {
          
        // creating variables for our views.
        private final ImageView imageIV;
  
        public RecyclerViewHolder(@NonNull View itemView) {
            super(itemView);
            // initializing our views with their ids.
            imageIV = itemView.findViewById(R.id.idIVImage);
        }
    }
}


Java
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.Toast;
  
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
  
import java.util.ArrayList;
  
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
  
public class MainActivity extends AppCompatActivity {
      
    // on below line we are creating variables for
    // our array list, recycler view and adapter class.
    private static final int PERMISSION_REQUEST_CODE = 200;
    private ArrayList imagePaths;
    private RecyclerView imagesRV;
    private RecyclerViewAdapter imageRVAdapter;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
          
        // we are calling a method to request
        // the permissions to read external storage.
        requestPermissions();
          
        // creating a new array list and
        // initializing our recycler view.
        imagePaths = new ArrayList<>();
        imagesRV = findViewById(R.id.idRVImages);
          
        // calling a method to 
        // prepare our recycler view.
        prepareRecyclerView();
    }
  
    private boolean checkPermission() {
        // in this method we are checking if the permissions are granted or not and returning the result.
        int result = ContextCompat.checkSelfPermission(getApplicationContext(), READ_EXTERNAL_STORAGE);
        return result == PackageManager.PERMISSION_GRANTED;
    }
  
    private void requestPermissions() {
        if (checkPermission()) {
            // if the permissions are already granted we are calling
            // a method to get all images from our external storage.
            Toast.makeText(this, "Permissions granted..", Toast.LENGTH_SHORT).show();
            getImagePath();
        } else {
            // if the permissions are not granted we are
            // calling a method to request permissions.
            requestPermission();
        }
    }
      
    private void requestPermission() {
        //on below line we are requesting the rea external storage permissions.
        ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
    }
  
    private void prepareRecyclerView() {
          
        // in this method we are preparing our recycler view.
        // on below line we are initializing our adapter class.
        imageRVAdapter = new RecyclerViewAdapter(MainActivity.this, imagePaths);
          
        // on below line we are creating a new grid layout manager.
        GridLayoutManager manager = new GridLayoutManager(MainActivity.this, 4);
          
        // on below line we are setting layout
        // manager and adapter to our recycler view.
        imagesRV.setLayoutManager(manager);
        imagesRV.setAdapter(imageRVAdapter);
    }
  
    private void getImagePath() {
        // in this method we are adding all our image paths 
        // in our arraylist which we have created.
        // on below line we are checking if the device is having an sd card or not.
        boolean isSDPresent = android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
  
        if (isSDPresent) {
              
            // if the sd card is present we are creating a new list in
            // which we are getting our images data with their ids.
            final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID};
              
            // on below line we are creating a new 
            // string to order our images by string.
            final String orderBy = MediaStore.Images.Media._ID;
              
            // this method will stores all the images
            // from the gallery in Cursor
            Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, orderBy);
              
            // below line is to get total number of images
            int count = cursor.getCount();
              
            // on below line we are running a loop to add 
            // the image file path in our array list.
            for (int i = 0; i < count; i++) {
                  
                // on below line we are moving our cursor position
                cursor.moveToPosition(i);
                  
                // on below line we are getting image file path
                int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
                  
                // after that we are getting the image file path
                // and adding that path in our array list.
                imagePaths.add(cursor.getString(dataColumnIndex));
            }
            imageRVAdapter.notifyDataSetChanged();
            // after adding the data to our 
            // array list we are closing our cursor.
            cursor.close();
        }
    }
  
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        // this method is called after permissions has been granted.
        switch (requestCode) {
            // we are checking the permission code.
            case PERMISSION_REQUEST_CODE:
                // in this case we are checking if the permissions are accepted or not.
                if (grantResults.length > 0) {
                    boolean storageAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    if (storageAccepted) {
                        // if the permissions are accepted we are displaying a toast message
                        // and calling a method to get image path.
                        Toast.makeText(this, "Permissions Granted..", Toast.LENGTH_SHORT).show();
                        getImagePath();
                    } else {
                        // if permissions are denied we are closing the app and displaying the toast message.
                        Toast.makeText(this, "Permissions denined, Permissions are required to use the app..", Toast.LENGTH_SHORT).show();
                    }
                }
                break;
        }
    }
}


XML


  
    
    
  


Java
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;
  
import androidx.appcompat.app.AppCompatActivity;
  
import com.squareup.picasso.Picasso;
  
import java.io.File;
  
public class ImageDetailActivity extends AppCompatActivity {
      
    // creating a string variable, image view variable 
    // and a variable for our scale gesture detector class.
    String imgPath;
    private ImageView imageView;
    private ScaleGestureDetector scaleGestureDetector;
      
    // on below line we are defining our scale factor.
    private float mScaleFactor = 1.0f;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_detail);
         
        // on below line getting data which we have passed from our adapter class.
        imgPath = getIntent().getStringExtra("imgPath");
          
        // initializing our image view.
        imageView = findViewById(R.id.idIVImage);
          
        // on below line we are initializing our scale gesture detector for zoom in and out for our image.
        scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
         
        // on below line we are getting our image file from its path.
        File imgFile = new File(imgPath);
          
        // if the file exists then we are loading that image in our image view.
        if (imgFile.exists()) {
            Picasso.get().load(imgFile).placeholder(R.drawable.ic_launcher_background).into(imageView);
        }
    }
  
    @Override
    public boolean onTouchEvent(MotionEvent motionEvent) {
        // inside on touch event method we are calling on
        // touch event method and pasing our motion event to it.
        scaleGestureDetector.onTouchEvent(motionEvent);
        return true;
    }
  
    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        // on below line we are creating a class for our scale
        // listener and  extending it with gesture listener.
        @Override
        public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
              
            // inside on scale method we are setting scale
            // for our image in our image view.
            mScaleFactor *= scaleGestureDetector.getScaleFactor();
            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
              
            // on below line we are setting 
            // scale x and scale y to our image view.
            imageView.setScaleX(mScaleFactor);
            imageView.setScaleY(mScaleFactor);
            return true;
        }
    }
}


由于我们一次要从存储中加载所有图像,因此我们必须在AndroidManifest.xml文件中的应用程序标签中添加2个属性。导航到AndroidManifest.xml文件,然后在清单文件的应用程序标记中的以下两行中添加。

XML格式

android:hardwareAccelerated="false"
android:largeHeap="true"

步骤4:使用activity_main.xml文件

导航到应用程序> res>布局> activity_main.xml,然后将以下代码添加到该文件中。以下是activity_main.xml文件的代码。

XML格式



  
    
    
  

步骤5:创建要在RecyclerView中显示的项目

导航至应用程序> res>布局>右键单击应用程序>新建>布局资源文件,然后创建一个新的布局资源文件。将该文件命名为card_layout,然后将以下代码添加到其中。在代码中添加了注释,以便更详细地了解。

XML格式



  
    
    
  

步骤6:创建一个新的活动以显示单个图像

导航到应用程序> Java >应用程序的程序包名称>右键单击它>新建>空活动,并将您的活动命名为ImageDetailActivity并创建一个新活动。我们将使用此活动来显示不同图像列表中的单个图像。

第7步:创建适配器类,以将数据设置到RecyclerView中的每个项目

导航到应用程序> Java >应用程序的程序包名称>右键单击它>新建Java类,并将您的类命名为RecyclerViewAdapter,然后将以下代码添加到其中。在代码中添加了注释,以便更详细地了解。

Java

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
  
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
  
import com.squareup.picasso.Picasso;
  
import java.io.File;
import java.util.ArrayList;
  
public class RecyclerViewAdapter extends RecyclerView.Adapter {
      
    // creating a variable for our context and array list.
    private final Context context;
    private final ArrayList imagePathArrayList;
  
    // on below line we have created a constructor.
    public RecyclerViewAdapter(Context context, ArrayList imagePathArrayList) {
        this.context = context;
        this.imagePathArrayList = imagePathArrayList;
    }
  
    @NonNull
    @Override
    public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // Inflate Layout in this method whch we have created.
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false);
        return new RecyclerViewHolder(view);
    }
  
    @Override
    public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
          
        // on below line we are getting th file from the
        // path which we have stored in our list.
        File imgFile = new File(imagePathArrayList.get(position));
          
        // on below line we are checking if tje file exists or not.
        if (imgFile.exists()) {
              
            // if the file exists then we are displaying that file in our image view using picasso library.
            Picasso.get().load(imgFile).placeholder(R.drawable.ic_launcher_background).into(holder.imageIV);
              
            // on below line we are adding click listener to our item of recycler view.
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                      
                    // inside on click listner we are creating a new intent
                    Intent i = new Intent(context, ImageDetailActivity.class);
                      
                    // on below line we are passing the image path to our new activity.
                    i.putExtra("imgPath", imagePathArrayList.get(position));
                      
                    // at last we are starting our activity.
                    context.startActivity(i);
                }
            });
        }
    }
  
    @Override
    public int getItemCount() {
        // this method returns 
        // the size of recyclerview
        return imagePathArrayList.size();
    }
  
    // View Holder Class to handle Recycler View.
    public static class RecyclerViewHolder extends RecyclerView.ViewHolder {
          
        // creating variables for our views.
        private final ImageView imageIV;
  
        public RecyclerViewHolder(@NonNull View itemView) {
            super(itemView);
            // initializing our views with their ids.
            imageIV = itemView.findViewById(R.id.idIVImage);
        }
    }
}

步骤8:使用MainActivity。 Java文件

转到MainActivity。 Java文件并参考以下代码。下面是MainActivity的代码。 Java文件。在代码内部添加了注释,以更详细地了解代码。

Java

import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.Toast;
  
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
  
import java.util.ArrayList;
  
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
  
public class MainActivity extends AppCompatActivity {
      
    // on below line we are creating variables for
    // our array list, recycler view and adapter class.
    private static final int PERMISSION_REQUEST_CODE = 200;
    private ArrayList imagePaths;
    private RecyclerView imagesRV;
    private RecyclerViewAdapter imageRVAdapter;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
          
        // we are calling a method to request
        // the permissions to read external storage.
        requestPermissions();
          
        // creating a new array list and
        // initializing our recycler view.
        imagePaths = new ArrayList<>();
        imagesRV = findViewById(R.id.idRVImages);
          
        // calling a method to 
        // prepare our recycler view.
        prepareRecyclerView();
    }
  
    private boolean checkPermission() {
        // in this method we are checking if the permissions are granted or not and returning the result.
        int result = ContextCompat.checkSelfPermission(getApplicationContext(), READ_EXTERNAL_STORAGE);
        return result == PackageManager.PERMISSION_GRANTED;
    }
  
    private void requestPermissions() {
        if (checkPermission()) {
            // if the permissions are already granted we are calling
            // a method to get all images from our external storage.
            Toast.makeText(this, "Permissions granted..", Toast.LENGTH_SHORT).show();
            getImagePath();
        } else {
            // if the permissions are not granted we are
            // calling a method to request permissions.
            requestPermission();
        }
    }
      
    private void requestPermission() {
        //on below line we are requesting the rea external storage permissions.
        ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
    }
  
    private void prepareRecyclerView() {
          
        // in this method we are preparing our recycler view.
        // on below line we are initializing our adapter class.
        imageRVAdapter = new RecyclerViewAdapter(MainActivity.this, imagePaths);
          
        // on below line we are creating a new grid layout manager.
        GridLayoutManager manager = new GridLayoutManager(MainActivity.this, 4);
          
        // on below line we are setting layout
        // manager and adapter to our recycler view.
        imagesRV.setLayoutManager(manager);
        imagesRV.setAdapter(imageRVAdapter);
    }
  
    private void getImagePath() {
        // in this method we are adding all our image paths 
        // in our arraylist which we have created.
        // on below line we are checking if the device is having an sd card or not.
        boolean isSDPresent = android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
  
        if (isSDPresent) {
              
            // if the sd card is present we are creating a new list in
            // which we are getting our images data with their ids.
            final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID};
              
            // on below line we are creating a new 
            // string to order our images by string.
            final String orderBy = MediaStore.Images.Media._ID;
              
            // this method will stores all the images
            // from the gallery in Cursor
            Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, orderBy);
              
            // below line is to get total number of images
            int count = cursor.getCount();
              
            // on below line we are running a loop to add 
            // the image file path in our array list.
            for (int i = 0; i < count; i++) {
                  
                // on below line we are moving our cursor position
                cursor.moveToPosition(i);
                  
                // on below line we are getting image file path
                int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
                  
                // after that we are getting the image file path
                // and adding that path in our array list.
                imagePaths.add(cursor.getString(dataColumnIndex));
            }
            imageRVAdapter.notifyDataSetChanged();
            // after adding the data to our 
            // array list we are closing our cursor.
            cursor.close();
        }
    }
  
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        // this method is called after permissions has been granted.
        switch (requestCode) {
            // we are checking the permission code.
            case PERMISSION_REQUEST_CODE:
                // in this case we are checking if the permissions are accepted or not.
                if (grantResults.length > 0) {
                    boolean storageAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    if (storageAccepted) {
                        // if the permissions are accepted we are displaying a toast message
                        // and calling a method to get image path.
                        Toast.makeText(this, "Permissions Granted..", Toast.LENGTH_SHORT).show();
                        getImagePath();
                    } else {
                        // if permissions are denied we are closing the app and displaying the toast message.
                        Toast.makeText(this, "Permissions denined, Permissions are required to use the app..", Toast.LENGTH_SHORT).show();
                    }
                }
                break;
        }
    }
}

步骤9:使用activity_image_detail.xml文件。

导航至应用程序> res>布局> activity_image_detail.xml,然后将以下代码添加到该文件中。以下是activity_image_detail.xml文件的代码

XML格式



  
    
    
  

步骤10:使用ImageDetailActivity。 Java文件

转到ImageDetailActivity。 Java文件并参考以下代码。下面是ImageDetailActivity的代码。 Java文件。在代码内部添加了注释,以更详细地了解代码。

Java

import android.os.Bundle;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;
  
import androidx.appcompat.app.AppCompatActivity;
  
import com.squareup.picasso.Picasso;
  
import java.io.File;
  
public class ImageDetailActivity extends AppCompatActivity {
      
    // creating a string variable, image view variable 
    // and a variable for our scale gesture detector class.
    String imgPath;
    private ImageView imageView;
    private ScaleGestureDetector scaleGestureDetector;
      
    // on below line we are defining our scale factor.
    private float mScaleFactor = 1.0f;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_detail);
         
        // on below line getting data which we have passed from our adapter class.
        imgPath = getIntent().getStringExtra("imgPath");
          
        // initializing our image view.
        imageView = findViewById(R.id.idIVImage);
          
        // on below line we are initializing our scale gesture detector for zoom in and out for our image.
        scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
         
        // on below line we are getting our image file from its path.
        File imgFile = new File(imgPath);
          
        // if the file exists then we are loading that image in our image view.
        if (imgFile.exists()) {
            Picasso.get().load(imgFile).placeholder(R.drawable.ic_launcher_background).into(imageView);
        }
    }
  
    @Override
    public boolean onTouchEvent(MotionEvent motionEvent) {
        // inside on touch event method we are calling on
        // touch event method and pasing our motion event to it.
        scaleGestureDetector.onTouchEvent(motionEvent);
        return true;
    }
  
    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        // on below line we are creating a class for our scale
        // listener and  extending it with gesture listener.
        @Override
        public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
              
            // inside on scale method we are setting scale
            // for our image in our image view.
            mScaleFactor *= scaleGestureDetector.getScaleFactor();
            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
              
            // on below line we are setting 
            // scale x and scale y to our image view.
            imageView.setScaleX(mScaleFactor);
            imageView.setScaleY(mScaleFactor);
            return true;
        }
    }
}

现在运行您的应用程序,并查看该应用程序的输出。

输出: