環境
- Windows10 21H2
- Android Studio Chipmunk | 2021.2.1 Patch 1
使用するライブラリ
- glide 4.13.2
今回は Java を使用して簡易的なギャラリーアプリを作っていきます。
完成するとこのようになります。
*記事中でこの部分が間違っているやこの方法の方が良いという部分がありましたら教えていただけると幸いです。
それでは始めましょう!
下準備
まずは、マニフェストファイルに<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
をapplication
タグの上に書き足します。
次にbuild.gradleにglideを追加します。
作成編
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_img"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
画面構成はシンプルでRecyclerViewが一つあるだけです。
次にRecyclerViewのアイテムのレイアウトを作っていきましょう。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/img_thumbnail"
android:layout_width="match_parent"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
ConstraintLayoutを親に持っていることでアスペクト比を指定できるようになるので(もしかしたら他の物でもできるかも)ImageViewにapp:layout_constraintDimensionRatio="1:1"
を指定して正方形にしています。
次にRecyclerViewを使用するためにViewHolderとAdapterを作成します。今回はコードがそこまで長くならないのでViewHolderとAdapterを一つのファイルに作ってしまいます。
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {
private Context context;
private List<String> pathList;
public ImageAdapter(Context context, List<String> pathList) {
this.context = context;
this.pathList = pathList;
}
@NonNull
@Override
public ImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.image_item, parent, false);
return new ImageViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ImageViewHolder holder, int position) {
String path = pathList.get(holder.getAdapterPosition());
Glide.with(context).load(new File(path)).into(holder.img_thumbnail);
// holder.img_thumbnail.setImageURI(Uri.parse(path));
}
@Override
public int getItemCount() {
return pathList.size();
}
class ImageViewHolder extends RecyclerView.ViewHolder {
public ImageView img_thumbnail;
public ImageViewHolder(@NonNull View itemView) {
super(itemView);
img_thumbnail = itemView.findViewById(R.id.img_thumbnail);
}
}
}
Adapterを簡単に説明すると、
onCreateViewHolder: ViewHolderを作成
onBindViewHolder: リストのアイテムにデータを流しこむところ
getItemCount: リストのアイテム数を指定
これでMainActivity.javaにコードを書いていく準備が終わりました。
それではMainActivity.javaにプログラムを書いていきましょう!
public class MainActivity extends AppCompatActivity {
private RecyclerView recycler_img;
private List<String> pathList;
private ImageAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recycler_img = findViewById(R.id.recycler_img);
recycler_img.setHasFixedSize(true);
recycler_img.setLayoutManager(new GridLayoutManager(this, 3));
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// パーミッションがまだ許可されていなかった場合
requestPermission.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
} else {
// パーミッションが既に許可されていた場合
appSetUP();
}
}
@SuppressLint("Range")
private void appSetUP() {
// リストの初期化
pathList = new ArrayList<>();
// UIスレッドで処理すると画面が一瞬固まるので別スレッド
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(new Runnable() {
@Override
public void run() {
// 画像の情報を取得してリストに追加する処理
Cursor cursor = getApplicationContext().getContentResolver()
.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
null,
null,
null
);
while(cursor.moveToNext()) {
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
pathList.add(path);
}
// 画像の情報を取得してリストに追加する処理 ここまで
// RecyclerViewのアダプターのインスタンスを作成
adapter = new ImageAdapter(MainActivity.this, pathList);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// UIスレッド以外からUIを更新するとエラーが出るのでHandlerを使ってUIスレッドで処理する
recycler_img.setAdapter(adapter);
}
});
}
});
}
// パーミッションをリクエストする処理
// requestPermission.launch(Manifest.permission.READ_EXTERNAL_STORAGE); のようにしてリクエストする
private final ActivityResultLauncher<String> requestPermission = registerForActivityResult(new ActivityResultContracts.RequestPermission(), result -> {
if(result) {
appSetUP();
} else {
Toast.makeText(this, "Read Storage permission is required", Toast.LENGTH_SHORT).show();
}
});
}
おわりに
最後まで読んで下さりありがとうございました。
そしてお疲れ様です。
今回作ったものは画像一覧を表示させるだけのアプリですが、これをベースに自分で改造していくことも可能です。
自分で改造してうまくいくと自信が付くので時間がある人は是非試してみてください。