Gallery 简易图片浏览

news/2024/10/17 14:20:20/

1. build.gradle, AndroidManifast.xml, 配置文件添加引用

  1.1 dependencies 中添加引用库

dependencies {//http 请求implementation 'com.android.volley:volley:1.2.1'//上拉刷新implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'//加载网络地址图片implementation 'com.github.bumptech.glide:glide:4.13.2'annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'def nav_version = "2.5.2"//Kotlin navigation 导航implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"implementation "androidx.navigation:navigation-ui-ktx:$nav_version"//gson 序列化implementation 'com.google.code.gson:gson:2.9.1'//加载图片时动画效果implementation 'io.supercharge:shimmerlayout:2.1.0'//图片缩放操作implementation 'com.github.chrisbanes:PhotoView:2.3.0'
}

  1.2 添加 com.github.chrisbanes:PhotoView:2.3.0 库,settings.gradle 需要添加引用

dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {google()mavenCentral()//添加引用maven { url "https://www.jitpack.io" }}
}

  1.3 视图与类绑定

android {buildFeatures {viewBinding = true}
}

  1.4 添加 @Parcelize 注解, 不用实现 Parcelable 里的方法

plugins {id 'kotlin-parcelize'
}

  1.5 AndroidManifest.xml 添加网络权限

   <uses-permission android:name="android.permission.INTERNET" /><application  android:usesCleartextTraffic="true">

  1.6 占位图 ic_baseline_photo_24.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:tint="#D8D9D9"android:viewportWidth="24"android:viewportHeight="24"><pathandroid:fillColor="@android:color/white"android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z" />
</vector>

  1.7 占位图 ic_photo_place_holder.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item><shape><solid android:color="#99999999" /><size android:width="40dp" android:height="30dp" /></shape></item>
</selector>

  1.8 占位图喜欢 ic_baseline_thumb_up.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="12dp"android:height="12dp"android:tint="#F50606"android:viewportWidth="24"android:viewportHeight="24"><pathandroid:fillColor="@android:color/white"android:pathData="M1,21h4L5,9L1,9v12zM23,10c0,-1.1 -0.9,-2 -2,-2h-6.31l0.95,-4.57 0.03,-0.32c0,-0.41 -0.17,-0.79 -0.44,-1.06L14.17,1 7.59,7.59C7.22,7.95 7,8.45 7,9v10c0,1.1 0.9,2 2,2h9c0.83,0 1.54,-0.5 1.84,-1.22l3.02,-7.05c0.09,-0.23 0.14,-0.47 0.14,-0.73v-2z" />
</vector>

  1.9 占位图收藏 ic_baseline_favorite.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="12dp"android:height="12dp"android:tint="#F50606"android:viewportWidth="24"android:viewportHeight="24"><pathandroid:fillColor="@android:color/white"android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z" />
</vector>

2. 创建 Gallery 主页

  2.1 布局文件 fragment_gallery.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/swipeLayoutGallery"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="2dp"tools:context=".GalleryFragment"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

  2.2 创建实体类,存放字段 Pixabay.kt

data class Pixabay(val total: Int,val totalHits: Int,val hits: Array<PhotoItem>
) {override fun equals(other: Any?): Boolean {if (this === other) return trueif (javaClass != other?.javaClass) return falseother as Pixabayif (total != other.total) return falseif (totalHits != other.totalHits) return falseif (!hits.contentEquals(other.hits)) return falsereturn true}override fun hashCode(): Int {var result = totalresult = 31 * result + totalHitsresult = 31 * result + hits.contentHashCode()return result}
}//@Parcelize:注解 不用实现 Parcelable 里的方法
@Parcelize data class PhotoItem(@SerializedName("id") val photoId: Int,@SerializedName("webformatURL") val previewUrl: String,@SerializedName("largeImageURL") val fullUrl: String,@SerializedName("webformatHeight") val photoHeight: Int,@SerializedName("user") val photoUser:String,@SerializedName("likes") val photoLikes: Int,@SerializedName("collections") val photoFavorites: Int
):Parcelable

  2.3 创建 RecyclerView 子 View,gallery_cell.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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="wrap_content"android:layout_margin="2dp"app:cardCornerRadius="2dp"><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/tv_user"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:layout_marginTop="8dp"android:text="TextView"android:textSize="14sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/shimmerLayoutCell" /><ImageViewandroid:id="@+id/imageView2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:layout_marginTop="8dp"android:layout_marginBottom="8dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/tv_user"app:srcCompat="@drawable/ic_baseline_thumb_up" /><TextViewandroid:id="@+id/tv_likes"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:text="TextView"android:textSize="10sp"app:layout_constraintBottom_toBottomOf="@+id/imageView2"app:layout_constraintStart_toEndOf="@+id/imageView2"app:layout_constraintTop_toTopOf="@+id/imageView2" /><ImageViewandroid:id="@+id/imageView3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"app:layout_constraintBottom_toBottomOf="@+id/tv_likes"app:layout_constraintStart_toEndOf="@+id/tv_likes"app:layout_constraintTop_toTopOf="@+id/tv_likes"app:srcCompat="@drawable/ic_baseline_favorite" /><TextViewandroid:id="@+id/tv_favorites"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="8dp"android:text="TextView"android:textSize="10sp"app:layout_constraintBottom_toBottomOf="@+id/imageView3"app:layout_constraintStart_toEndOf="@+id/imageView3"app:layout_constraintTop_toTopOf="@+id/imageView3" /><io.supercharge.shimmerlayout.ShimmerLayoutandroid:id="@+id/shimmerLayoutCell"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"><ImageViewandroid:id="@+id/imageView"android:layout_width="match_parent"android:layout_height="wrap_content"android:adjustViewBounds="true"android:scaleType="centerCrop"tools:srcCompat="@tools:sample/avatars" /></io.supercharge.shimmerlayout.ShimmerLayout></androidx.constraintlayout.widget.ConstraintLayout></androidx.cardview.widget.CardView>

2.4 创建 RecyclerView 适配器, GalleryAdapter.kt

class GalleryAdapter: ListAdapter<PhotoItem, MyViewHolder>(DIFFCALLBACK) {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {val holder = MyViewHolder(GalleryCellBinding.inflate(LayoutInflater.from(parent.context), parent, false))holder.itemView.setOnClickListener {Bundle().apply {//putParcelable("PHOTO", getItem(holder.adapterPosition))//holder.itemView.findNavController().navigate(R.id.action_galleryFragment_to_photoFragment,this)//val list = ArrayList(snapshot())putParcelableArrayList("PHOTO_LIST", ArrayList(currentList))//putParcelableArrayList("PHOTO_LIST", ArrayList(snapshot()))putInt("PHOTO_POSITION", holder.adapterPosition)holder.itemView.findNavController().navigate(R.id.action_galleryFragment_to_pagerPhotoFragment, this)}}return holder}override fun onBindViewHolder(holder: MyViewHolder, position: Int) {val photoItem = getItem(position)?: returnval cellBinding = holder.binding as GalleryCellBindingwith(cellBinding){shimmerLayoutCell.apply {setShimmerColor(0x55FFFFFF)setShimmerAngle(0)startShimmerAnimation()}tvUser.text = photoItem.photoUsertvLikes.text = photoItem.photoLikes.toString()tvFavorites.text = photoItem.photoFavorites.toString()imageView.layoutParams.height = photoItem.photoHeight}Glide.with(holder.itemView).load(getItem(position)?.previewUrl).placeholder(R.drawable.ic_photo_place_holder).listener(object : RequestListener<Drawable> {override fun onLoadFailed(e: GlideException?,model: Any?,target: Target<Drawable>?,isFirstResource: Boolean): Boolean {return false}override fun onResourceReady(resource: Drawable?,model: Any?,target: Target<Drawable>?,dataSource: DataSource?,isFirstResource: Boolean): Boolean {return false.also { cellBinding.shimmerLayoutCell.stopShimmerAnimation() }}}).into(cellBinding.imageView)}object DIFFCALLBACK : DiffUtil.ItemCallback<PhotoItem>() {override fun areItemsTheSame(oldItem: PhotoItem, newItem: PhotoItem): Boolean {return oldItem == newItem}override fun areContentsTheSame(oldItem: PhotoItem, newItem: PhotoItem): Boolean {return oldItem.photoId == newItem.photoId}}
}class MyViewHolder(binding: ViewBinding) : ViewHolder(binding.root) {val binding = binding
}

  2.5 封装网络请求类,VolleySingleton.kt

//单例模式
class VolleySingleton private constructor(context: Context) {companion object {private var INSTANCE: VolleySingleton? = nullfun getInstance(context: Context) =INSTANCE ?: synchronized(this) {VolleySingleton(context).also { INSTANCE = it }}}val requestQueue: RequestQueue by lazy {Volley.newRequestQueue(context.applicationContext)}
}

  2.6 创建菜单栏布局,刷新图片内容 menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@+id/swipeIndicator"android:title="swipe to refresh" />
</menu>

  2.7 创建 ViewModel 监听数据,GalleryViewModel.kt

class GalleryViewModel(application: Application) : AndroidViewModel(application) {private val TAG = GalleryViewModel::class.java.simpleNameprivate var _photoListLive = MutableLiveData<List<PhotoItem>>()val photoListLive: LiveData<List<PhotoItem>>get() = _photoListLivefun fetchData() {val stringRequest = StringRequest(Request.Method.GET,getUrl(),{_photoListLive.value = Gson().fromJson(it, Pixabay::class.java).hits.toList();},{Log.e(TAG, "onErrorResponse", it)})VolleySingleton.getInstance(getApplication()).requestQueue.add(stringRequest)}private fun getUrl(): String {//&per_page=100return "https://pixabay.com/api/?key=30070990-cfc31c9f778ceeef4009d910d&q=${keyWords.random()}"}private val keyWords =arrayOf("cat", "dog", "car", "beauty", "phone", "computer", "flower", "animal")
}

  2.8 主页调用 GalleryFragment.kt

class GalleryFragment : Fragment() {private lateinit var binding: FragmentGalleryBindingprivate lateinit var galleryViewModel: GalleryViewModeloverride fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {binding = FragmentGalleryBinding.inflate(inflater, container, false)return binding.root}override fun onOptionsItemSelected(item: MenuItem): Boolean {when (item.itemId) {R.id.swipeIndicator -> {binding.swipeLayoutGallery.isRefreshing = trueHandler().postDelayed(Runnable { galleryViewModel.fetchData() }, 700)}}return super.onOptionsItemSelected(item)}//加载菜单栏override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {super.onCreateOptionsMenu(menu, inflater)inflater.inflate(R.menu.menu, menu)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)setHasOptionsMenu(true)val galleryAdapter = GalleryAdapter()binding.recyclerView?.apply {adapter = galleryAdapter//GridLayouStaager(requireContext(), 2) 对齐 / StaggeredGridLayoutManager 交错感layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)}//,ViewModelProvider.AndroidViewModelFactory(requireActivity().application)galleryViewModel = ViewModelProvider(this)[GalleryViewModel::class.java]galleryViewModel.photoListLive.observe(viewLifecycleOwner, Observer {galleryAdapter.submitList(it)binding.swipeLayoutGallery.isRefreshing = false})galleryViewModel.photoListLive.value ?: galleryViewModel.fetchData()binding.swipeLayoutGallery?.setOnRefreshListener {galleryViewModel.fetchData()}}
}

3. Photo 详情页

  3.1 布局文件 fragment_photo.xml

<?xml version="1.0" encoding="utf-8"?>
<io.supercharge.shimmerlayout.ShimmerLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/shimmerLayoutPhoto"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".PhotoFragment" ><com.github.chrisbanes.photoview.PhotoViewandroid:id="@+id/photoView"android:layout_width="match_parent"android:layout_height="match_parent"android:adjustViewBounds="true"tools:src="@tools:sample/avatars" />
</io.supercharge.shimmerlayout.ShimmerLayout>

  3.2 调用类,PhotoFragment.kt

class PhotoFragment : Fragment() {private lateinit var binding: FragmentPhotoBindingoverride fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {binding = FragmentPhotoBinding.inflate(inflater, container, false);return binding.root}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)binding.shimmerLayoutPhoto.apply {setShimmerColor(0x55FFFFFF)setShimmerAngle(0)startShimmerAnimation()}val item = arguments?.getParcelable<PhotoItem>("PHOTO")Glide.with(requireContext()).load(item?.fullUrl).placeholder(R.drawable.ic_baseline_photo_24).listener(object : RequestListener<Drawable> {override fun onLoadFailed(e: GlideException?,model: Any?,target: Target<Drawable>?,isFirstResource: Boolean): Boolean {return false}override fun onResourceReady(resource: Drawable?,model: Any?,target: Target<Drawable>?,dataSource: DataSource?,isFirstResource: Boolean): Boolean {return false.also { binding.shimmerLayoutPhoto.stopShimmerAnimation() }}}).into(binding.photoView)}
}

4. Activity 调用

  4.1 Fragment 导航布局, navigation.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/navigation"app:startDestination="@id/galleryFragment"><fragmentandroid:id="@+id/galleryFragment"android:name="com.example.gallery.GalleryFragment"android:label="Gallery"tools:layout="@layout/fragment_gallery"><actionandroid:id="@+id/action_galleryFragment_to_photoFragment"app:destination="@id/photoFragment" /></fragment><fragmentandroid:id="@+id/photoFragment"android:name="com.example.gallery.PhotoFragment"android:label="Photo"tools:layout="@layout/fragment_photo" />
</navigation>

  4.2 布局文件 activity_main.xml

<?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.fragment.app.FragmentContainerViewandroid:id="@+id/fragmentContainerView"android:name="androidx.navigation.fragment.NavHostFragment"android:layout_width="match_parent"android:layout_height="match_parent"app:defaultNavHost="true"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:navGraph="@navigation/navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>

  4.3 调用页 MainActivity.kt

class MainActivity : AppCompatActivity() {private lateinit var controller:NavHostFragmentoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)//添加返回按键controller = supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragmentNavigationUI.setupActionBarWithNavController(this,controller.navController)}//返回按键监听override fun onSupportNavigateUp(): Boolean {return super.onSupportNavigateUp()||controller.navController.navigateUp()}
}

5. 效果图

    

 

 


http://www.ppmy.cn/news/150211.html

相关文章

照片浏览

照片浏览器&#xff1a; 1&#xff0c;SDPhotoBrowser 链接&#xff1a; https://github.com/gsdios/SDPhotoBrowser 介绍&#xff1a;中国人提供的源码&#xff0c;是在sdimage上进行开发的&#xff1b;可以查看网络图片&#xff0c;并且有图片缓存功能&#xff0c;加载一次后…

XnViewMP图片浏览器

今天小编给大家带来的是XnViewMP图片浏览器&#xff0c;这是一款非常棒的完全免费图片浏览器&#xff0c;同时支持多种语言&#xff0c;并且是纯绿色免安装&#xff0c;即下即用。软件支持100多种图片格式&#xff0c;还具有浏览器、幻灯片、屏幕捕捉、缩略图制作、批处理转换、…

页面图片浏览

在页面上浏览图片&#xff0c;实现图片的拖放 <html><head><meta http-equiv"Content-Type" content"text/html; charsetgb2312"><title>位图浏览器</title><style type"text/css"><!--#pic { width:…

Js图片浏览器

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns"http://www.w3.org/1999/xhtml"> <head> <title>Js图片浏览器</title&…

照片浏览器

昨天写了个图片浏览器&#xff0c;很简单&#xff0c;主要就是用一个JFileChooser导入一个文件&#xff0c;然后在文件父目录下导入下一个 或者上一个图像。 东西做好了&#xff0c;但是还有一个问题&#xff0c;就是我界面图片的路径设置有问题&#xff0c;在打成Jar包后就不能…

浏览器加载本地图片并预览

function imgPreview(config) {var width config.width || 200;var height config.height || 200;return {/*** ie9- 预览图片* param {type} input_file ,$(input[typefile]) 或者 $(input[typefile])[0]* param {type} callback 回掉参数为&#xff0c;$(居中的图片)* retu…

【Android】简单图片浏览器

开始重新学习Android&#xff0c;还是依照《疯狂Android讲义》。 简单图片浏览器&#xff1a; 功能&#xff1a;图片浏览器&#xff0c;点击图片可以切换。 注意&#xff1a;在res/drawable中添加p1.jpg、p2.jpg、p3.jpg。 Java代码&#xff1a; import android.support.v7.…

网页图片浏览器

公司有个需求是一个webview页面里的图片点击会放大&#xff0c;支持保存功能&#xff0c;在网上找了很多资料&#xff0c;也没用一个合适的&#xff0c;决定自己写一个&#xff0c;效果如下&#xff1a; 废话不多说&#xff0c;先上代码&#xff1a;实现代码 ####实现思路&…