Android仿微信聊天圖片的放大縮小功能
一、前言
經(jīng)常會遇到類似微信聊天圖片點擊放大縮小的效果,從點擊位置的圖片放大,再點擊縮小回去原位置的效果,查找過網(wǎng)上代碼,不過可參考比較少,這里將Android官方代碼進行略作修改有了以下代碼。
效果如下:

二、核心源碼
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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android編程使WebView支持HTML5 Video全屏播放的解決方法
這篇文章主要介紹了Android編程使WebView支持HTML5 Video全屏播放的解決方法,較為詳細的分析了全屏播放所涉及的相關(guān)技巧,并給出了完整代碼下載地址供讀者參考,需要的朋友可以參考下2015-10-10
Android編程計算函數(shù)時間戳的相關(guān)方法總結(jié)
這篇文章主要介紹了Android編程計算函數(shù)時間戳的相關(guān)方法,結(jié)合實例形式總結(jié)分析了Android Java、Native、Kernel時間戳計算相關(guān)操作技巧,需要的朋友可以參考下2017-05-05
Android 判斷某個Activity 是否在前臺運行的實例
下面小編就為大家分享一篇Android 判斷某個Activity 是否在前臺運行的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03
android 把float轉(zhuǎn)換成Int的實例講解
今天小編就為大家分享一篇android 把float轉(zhuǎn)換成Int的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07
快速解決fragment中onActivityResult不調(diào)用的問題
下面小編就為大家?guī)硪黄焖俳鉀Qfragment中onActivityResult不調(diào)用的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04
Android編程之手機壁紙WallPaper設(shè)置方法示例
這篇文章主要介紹了Android編程之手機壁紙WallPaper設(shè)置方法,結(jié)合實例形式分析了Android手機壁紙WallPaper的相關(guān)設(shè)置與使用技巧,需要的朋友可以參考下2017-08-08

