Android仿微信聊天圖片的放大縮小功能
一、前言
經(jīng)常會(huì)遇到類似微信聊天圖片點(diǎn)擊放大縮小的效果,從點(diǎn)擊位置的圖片放大,再點(diǎn)擊縮小回去原位置的效果,查找過網(wǎng)上代碼,不過可參考比較少,這里將Android官方代碼進(jìn)行略作修改有了以下代碼。
效果如下:
二、核心源碼
item_zoom.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout 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="wrap_content" android:layout_height="wrap_content"> <ImageButton android:id="@+id/thumb_button_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="1dp" android:contentDescription="@string/description_image_1" android:scaleType="centerCrop" android:src="@drawable/ic_main_img" /> </FrameLayout>
activity_zoom_list.xml
<FrameLayout 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/container" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_room" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="3" tools:listitem="@layout/item_zoom"/> <!-- This initially hidden ImageView holds the zoomed version of the preceding images. Without transformations applied, it fills the entire screen. To achieve the zoom animation, this view's bounds are animated from the bounds of the preceding thumbnail button to its final laid-out bounds. --> <ImageView android:id="@+id/expanded_image" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" android:contentDescription="@string/description_zoom_touch_close" /> </FrameLayout>
ZoomAdapter.kt
class ZoomAdapter: RecyclerView.Adapter<ZoomAdapter.VH>() { var itemClick: ( (View) -> Unit ) ?= null inner class VH(binding: ItemZoomBinding): RecyclerView.ViewHolder(binding.root) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH { val layoutInflater = LayoutInflater.from(parent.context) val binding = ItemZoomBinding.inflate(layoutInflater,parent,false) binding.thumbButton1.setOnClickListener { itemClick?.invoke(it) } return VH(binding) } override fun onBindViewHolder(holder: VH, position: Int) { } override fun getItemCount(): Int = 3 }
ZoomActivity.kt
/** * 仿寫微信應(yīng)用中圖片放大縮小效果 */ class ZoomActivity: FragmentActivity() { // Hold a reference to the current animator so that it can be canceled // midway. private var currentAnimator: Animator? = null // The system "short" animation time duration in milliseconds. This duration // is ideal for subtle animations or animations that occur frequently. private var shortAnimationDuration: Int = 0 private val binding: ActivityZoomListBinding by lazy { ActivityZoomListBinding.inflate(layoutInflater) } private val adapter = ZoomAdapter() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) // Retrieve and cache the system's default "short" animation time. shortAnimationDuration = resources.getInteger(android.R.integer.config_shortAnimTime) initView() } private fun initView(){ binding.rvRoom.adapter = adapter // Hook up taps on the thumbnail views. adapter.itemClick = { zoomImageFromThumb(it, R.drawable.ic_main_img) } } private fun zoomImageFromThumb(thumbView: View, imageResId: Int) { // If there's an animation in progress, cancel it immediately and // proceed with this one. currentAnimator?.cancel() // Load the high-resolution "zoomed-in" image. binding.expandedImage.setImageResource(imageResId) // Calculate the starting and ending bounds for the zoomed-in image. val startBoundsInt = Rect() val finalBoundsInt = Rect() val globalOffset = Point() // The start bounds are the global visible rectangle of the thumbnail, // and the final bounds are the global visible rectangle of the // container view. Set the container view's offset as the origin for the // bounds, since that's the origin for the positioning animation // properties (X, Y). thumbView.getGlobalVisibleRect(startBoundsInt) binding.container.getGlobalVisibleRect(finalBoundsInt, globalOffset) startBoundsInt.offset(-globalOffset.x, -globalOffset.y) finalBoundsInt.offset(-globalOffset.x, -globalOffset.y) val startBounds = RectF(startBoundsInt) val finalBounds = RectF(finalBoundsInt) // Using the "center crop" technique, adjust the start bounds to be the // same aspect ratio as the final bounds. This prevents unwanted // stretching during the animation. Calculate the start scaling factor. // The end scaling factor is always 1.0. val startScale: Float if ((finalBounds.width() / finalBounds.height() > startBounds.width() / startBounds.height())) { // Extend start bounds horizontally. startScale = startBounds.height() / finalBounds.height() val startWidth: Float = startScale * finalBounds.width() val deltaWidth: Float = (startWidth - startBounds.width()) / 2 startBounds.left -= deltaWidth.toInt() startBounds.right += deltaWidth.toInt() } else { // Extend start bounds vertically. startScale = startBounds.width() / finalBounds.width() val startHeight: Float = startScale * finalBounds.height() val deltaHeight: Float = (startHeight - startBounds.height()) / 2f startBounds.top -= deltaHeight.toInt() startBounds.bottom += deltaHeight.toInt() } // Hide the thumbnail and show the zoomed-in view. When the animation // begins, it positions the zoomed-in view in the place of the // thumbnail. thumbView.alpha = 0f animateZoomToLargeImage(startBounds, finalBounds, startScale) setDismissLargeImageAnimation(thumbView, startBounds, startScale) } private fun animateZoomToLargeImage(startBounds: RectF, finalBounds: RectF, startScale: Float) { binding.expandedImage.visibility = View.VISIBLE // Set the pivot point for SCALE_X and SCALE_Y transformations to the // top-left corner of the zoomed-in view. The default is the center of // the view. binding.expandedImage.pivotX = 0f binding.expandedImage.pivotY = 0f // Construct and run the parallel animation of the four translation and // scale properties: X, Y, SCALE_X, and SCALE_Y. currentAnimator = AnimatorSet().apply { play( ObjectAnimator.ofFloat( binding.expandedImage, View.X, startBounds.left, finalBounds.left) ).apply { with(ObjectAnimator.ofFloat(binding.expandedImage, View.Y, startBounds.top, finalBounds.top)) with(ObjectAnimator.ofFloat(binding.expandedImage, View.SCALE_X, startScale, 1f)) with(ObjectAnimator.ofFloat(binding.expandedImage, View.SCALE_Y, startScale, 1f)) } duration = shortAnimationDuration.toLong() interpolator = DecelerateInterpolator() addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { currentAnimator = null } override fun onAnimationCancel(animation: Animator) { currentAnimator = null } }) start() } } private fun setDismissLargeImageAnimation(thumbView: View, startBounds: RectF, startScale: Float) { // When the zoomed-in image is tapped, it zooms down to the original // bounds and shows the thumbnail instead of the expanded image. binding.expandedImage.setOnClickListener { currentAnimator?.cancel() // Animate the four positioning and sizing properties in parallel, // back to their original values. currentAnimator = AnimatorSet().apply { play(ObjectAnimator.ofFloat(binding.expandedImage, View.X, startBounds.left)).apply { with(ObjectAnimator.ofFloat(binding.expandedImage, View.Y, startBounds.top)) with(ObjectAnimator.ofFloat(binding.expandedImage, View.SCALE_X, startScale)) with(ObjectAnimator.ofFloat(binding.expandedImage, View.SCALE_Y, startScale)) } duration = shortAnimationDuration.toLong() interpolator = DecelerateInterpolator() addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { thumbView.alpha = 1f binding.expandedImage.visibility = View.GONE currentAnimator = null } override fun onAnimationCancel(animation: Animator) { thumbView.alpha = 1f binding.expandedImage.visibility = View.GONE currentAnimator = null } }) start() } } } }
三、參考鏈接:
到此這篇關(guān)于Android仿微信聊天圖片的放大縮小效果的文章就介紹到這了,更多相關(guān)Android微信聊天圖片放大縮小內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
android自定義view實(shí)現(xiàn)鐘表效果
這篇文章主要為大家詳細(xì)介紹了android自定義view實(shí)現(xiàn)鐘表效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12android中可以通過兩種方式調(diào)用接口發(fā)送短信
調(diào)用系統(tǒng)短信接口直接發(fā)送短信;調(diào)起系統(tǒng)發(fā)短信功能,本文將給出兩種方式的實(shí)現(xiàn)代碼,感興趣的朋友可以了解下,或許對(duì)你有所幫助2013-02-02Android TabLayout實(shí)現(xiàn)京東詳情效果
這篇文章主要為大家詳細(xì)介紹了android TabLayout實(shí)現(xiàn)京東詳情效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09android實(shí)現(xiàn)可以滑動(dòng)的平滑曲線圖
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)可以滑動(dòng)的平滑曲線圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06Android開發(fā)之模仿微信打開網(wǎng)頁的進(jìn)度條效果(高仿)
這篇文章主要介紹了Android開發(fā)之模仿微信打開網(wǎng)頁的進(jìn)度條效果(高仿)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07Android Studio3.6.3 當(dāng)前最新版本數(shù)據(jù)庫查找與導(dǎo)出方法(圖文詳解)
這篇文章主要介紹了Android Studio3.6.3 當(dāng)前最新版本數(shù)據(jù)庫查找與導(dǎo)出方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Android 游戲引擎libgdx 資源加載進(jìn)度百分比顯示案例分析
因?yàn)榘咐容^簡(jiǎn)單,所以簡(jiǎn)單用AndroidApplication -> Game -> Stage 搭建框架感興趣的朋友可以參考下2013-01-01使用Chrome瀏覽器調(diào)試Android App詳解
這篇文章主要介紹了使用Chrome瀏覽器調(diào)試Android App詳解,本網(wǎng)講解了使用Facebook開源Stetho實(shí)現(xiàn)在Chrome中調(diào)試Android App中,需要的朋友可以參考下2015-05-05