突然发现微信下拉小程序入口动画非常细腻,比较好奇,所以仿照他做了一个,并不是很完美,部分效果还没完成,但总体自我感觉还不错,效果见下文
还要增加一个用来填充状态栏的View,他的高度是动态获取的,整体布局是RelativeLayout,因为可以方便的设置中间View在状态下面和在导航栏上面。
class ViewUtils {
companion object{
@JvmStatic
fun getStatusBarHeight(resources: Resources): Int {
var result = 0
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId)
}
return result
}
}
}
小程序缩放比例值计算
然后要做的就是拖动View,可以借助ViewDragHelper来完成,当拖动会话布局的时候,小程序的布局开始做一个缩放比例动画,这个缩放值我在这是这样做的,因为不可能是从0开始,要从一个基础值开始,这个基础值就是0.8,那么剩下0.2的缩放值,就是从开始下拉算起,到整体的高度的百分比。
比如屏幕高度是1000,下拉到500的时候,那么这个缩放值就是0.1,在加上基础值0.8,计算方式如下,整体高度还要减去导航栏的高度。
var divide = BigDecimal(top.toString()).divide(BigDecimal(measuredHeight-NAVIGAATION_HEIGHT), 4, BigDecimal.ROUND_HALF_UP)
divide = divide.multiply(BigDecimal("100"))
divide = divide.multiply(BigDecimal("0.002" ))
divide = divide.add(BigDecimal("0.8"))
if (!isOpen) {
programView.scaleX = divide.toFloat()
programView.scaleY = divide.toFloat()
} else {
programView.top = paddingTop + (-((measuredHeight - NAVIGAATION_HEIGHT) - top))
}
这里就注意细节了,下拉的时候,小程序布局是通过缩放呈现的,但是上滑关闭的时,小程序布局是和会话布局同时向上走的。
动画遮罩
这是比较麻烦的一步,就是绘制进度动画,也就是那三个圆点。
这个原点有三种状态,一是出现时从小到大,二是到一定大小后,分离出两个固定大小的圆,但是这两个圆比此时中间的要小,并且和下拉进度慢慢向两边扩撒,三是中间的圆开始缩小,直到和其余两个圈同等大小。
这里就要另一波细节了,当还在屏幕的三分之一下拉时,这个头部遮罩布局整体还是不透明的,但是到屏幕的三分之一时,这个布局的透明度开始从255到0运动。并且到达三分之一的时候,还要振动一下,并且只要振动过了,那么在手指未松开时,再次到达屏幕的三分之一时,不会产生振动。
还有一波细节,状态栏由于使用了View填充,所以,从屏幕三份之一后开始,这个View的透明度也要从255-0开始运动。
完整代码如下。
package com.example.kotlindemo.widget.weixin
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.os.VibrationEffect
import android.os.Vibrator
import android.util.AttributeSet
import android.util.Log
import android.view.View
import androidx.core.content.ContextCompat
import com.example.kotlindemo.MainActivity
import com.example.kotlindemo.R
class WeiXinPullHeaderMaskView @JvmOverloads constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int
) :
View(context, attrs, defStyleAttr) {
var isVibrator: Boolean = false;
var progress: Int = 0;
var maxHeight: Int = 0;
private val CIRCLE_MAX_SIZE = 32;
var parentHeight=0;
var paint = Paint()
private val DEFAULT_CIRCLE_SIZE=8f;
init {
setBackgroundColor(Color.argb(255 , 239, 239, 239))
paint.alpha=255;
paint.color = ContextCompat.getColor(context!!, R.color.circleColor)
paint.isAntiAlias = true;
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
var value = height.toFloat() / maxHeight
if (height <= maxHeight / 2) {
canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), CIRCLE_MAX_SIZE * value, paint)
} else {
if (progress<100){
var diff = (value - 0.5f) * CIRCLE_MAX_SIZE
canvas.drawCircle(((width / 2).toFloat()-((0.4f-value)*100)), (height / 2).toFloat(), DEFAULT_CIRCLE_SIZE, paint)
canvas.drawCircle(((width / 2).toFloat()+((0.4f-value)*100)), (height / 2).toFloat(), DEFAULT_CIRCLE_SIZE, paint)
if ((CIRCLE_MAX_SIZE * 0.5f) - diff<=DEFAULT_CIRCLE_SIZE){
canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), DEFAULT_CIRCLE_SIZE, paint)
}else{
canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), (CIRCLE_MAX_SIZE * 0.5f) - diff, paint)
}
}else{
paint.alpha=getAlphaValue();
canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), DEFAULT_CIRCLE_SIZE, paint)
canvas.drawCircle((width / 2).toFloat()-((0.4f)*100), (height / 2).toFloat(), DEFAULT_CIRCLE_SIZE, paint)
canvas.drawCircle((width / 2).toFloat()+(((0.4f)*100)), (height / 2).toFloat(), DEFAULT_CIRCLE_SIZE, paint)
}
}
}
private fun getAlphaValue():Int{
val dc=parentHeight/3-ViewUtils.getStatusBarHeight(resources);
val alpha=((height).toFloat()-dc)/(parentHeight-(dc))
return 255-(255*alpha).toInt()
}
private fun vibrator() {
var vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
var createOneShot = VibrationEffect.createOneShot(7, 255)
vibrator.vibrate(createOneShot)
} else {
vibrator.vibrate(7)
}
}
fun setProgress(value: Float,parentHeight:Int) {
this.progress = value.toInt();
this.parentHeight=parentHeight;
if (value >= 100 && !isVibrator) {
vibrator()
isVibrator = true;
}
if (value < 100) {
isVibrator = false;
}
if (progress>=100){
setBackgroundColor(Color.argb(getAlphaValue() , 239, 239, 239))
var mainActivity = context as MainActivity
mainActivity.changeStatusBackgroundAlphaValue(getAlphaValue())
}else{
setBackgroundColor(Color.argb(255, 239, 239, 239))
}
invalidate()
}
}
还有就是这三个原点是始终位于遮罩View中间的,绘制的时候只需要在中间绘制,遮罩View的高度会被外界View所更改。
MainActivity
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.kotlindemo.databinding.ActivityMainBinding
import com.example.kotlindemo.widget.weixin.ChatSession
import com.example.kotlindemo.widget.weixin.ChatSessionAdapter
import com.example.kotlindemo.widget.weixin.ViewUtils
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding;
fun changeStatusBackgroundAlphaValue(value: Int){
binding.statusBar.setBackgroundColor(Color.argb(value, 239, 239, 239))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main);
var layoutParams = binding.statusBar.layoutParams
layoutParams.height=ViewUtils.getStatusBarHeight(resources)
binding.statusBar.layoutParams=layoutParams
binding.wxMain.setPadding(0, ViewUtils.getStatusBarHeight(resources), 0, 0)
if (Build.VERSION.SDK_INT >= 21) {
val window: Window = window
window.getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
)
window.setStatusBarColor(Color.TRANSPARENT)
}
val chatSessions= mutableListOf<ChatSession>()
for (index in 0 .. 10){
chatSessions.add(ChatSession("https://img2.baidu.com/it/u=3538084390,1079314259&fm=26&fmt=auto&gp=0.jpg","马云","你来,我把公司给你","上午"))
chatSessions.add(ChatSession("https://img0.baidu.com/it/u=273576249,1042072491&fm=26&fmt=auto&gp=0.jpg","奥巴马","哥哥在哪呢","上午"))
chatSessions.add(ChatSession("https://img1.baidu.com/it/u=152902017,4157746361&fm=11&fmt=auto&gp=0.jpg","成龙","马上接你","上午"))
chatSessions.add(ChatSession("https://img0.baidu.com/it/u=3789809038,289359647&fm=26&fmt=auto&gp=0.jpg","窃瓦辛格","我教你啊","上午"))
}
binding.chatList.adapter=ChatSessionAdapter(chatSessions,this)
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
</data>
<RelativeLayout
android:background="@drawable/program_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.example.kotlindemo.widget.weixin.WeiXinMainPullViewGroup
android:paddingTop="40dp"
android:layout_above="@+id/navigation"
android:id="@+id/wx_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.example.kotlindemo.widget.weixin.WeiXinProgram
android:paddingLeft="30dp"
android:paddingRight="30dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:textSize="17sp"
android:textColor="#C8C8C8"
android:gravity="center"
android:text="最近"
android:layout_width="match_parent"
android:layout_height="40dp"></TextView>
<androidx.cardview.widget.CardView
android:background="#424459"
app:cardBackgroundColor="#424459"
app:cardElevation="0dp"
app:cardCornerRadius="8dp"
android:layout_width="match_parent"
android:layout_height="46dp">
<LinearLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:textSize="15sp"
android:textColor="#C8C8C8"
android:text="搜索小程序"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</LinearLayout>
</androidx.cardview.widget.CardView>
<com.example.kotlindemo.widget.weixin.ProgramGridLayout
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.example.kotlindemo.widget.weixin.ProgramGridLayout>
<com.example.kotlindemo.widget.weixin.ProgramGridLayout
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.example.kotlindemo.widget.weixin.ProgramGridLayout>
</com.example.kotlindemo.widget.weixin.WeiXinProgram>
<com.example.kotlindemo.widget.weixin.WeiXinMainLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="@color/navigation_color">
<TextView
android:textStyle="bold"
android:textSize="16sp"
android:textColor="#000000"
android:layout_centerInParent="true"
android:gravity="center"
android:text="微信(323)"
android:layout_width="wrap_content"
android:layout_height="match_parent"></TextView>
<ImageView
android:layout_marginRight="45dp"
android:scaleType="center"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:src="QGRyYXdhYmxlL2ljX3NlYXJjaA=="
android:layout_width="28dp"
android:layout_height="28dp"></ImageView>
<ImageView
android:layout_marginRight="10dp"
android:scaleType="center"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:src="QGRyYXdhYmxlL2ljX2FkZA=="
android:layout_width="28dp"
android:layout_height="28dp">
</ImageView>
</RelativeLayout>
<com.example.kotlindemo.widget.weixin.WeiXinChatSessionListView
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:dividerHeight="10dp"
android:id="@+id/chat_list"
android:background="#FBFAFA"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.kotlindemo.widget.weixin.WeiXinChatSessionListView>
</com.example.kotlindemo.widget.weixin.WeiXinMainLayout>
</com.example.kotlindemo.widget.weixin.WeiXinMainPullViewGroup>
<LinearLayout
android:background="@color/navigation_color"
android:orientation="vertical"
android:id="@+id/navigation"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="60dp">
</LinearLayout>
<View
android:background="@color/navigation_color"
android:id="@+id/status_bar"
android:layout_width="match_parent"
android:layout_height="100dp"></View>
</RelativeLayout>
</layout>
以上就是Android 仿微信小程序入口动画的详细内容,更多关于Android 微信小程序入口动画的资料请关注编程学习网其它相关文章!
本文标题为:Android 仿微信小程序入口动画
- 作为iOS开发,这道面试题你能答出来,说明你基础很OK! 2023-09-14
- Flutter实现底部和顶部导航栏 2022-08-31
- 最好用的ios数据恢复软件:PhoneRescue for Mac 2023-09-14
- Android实现监听音量的变化 2023-03-30
- SurfaceView播放视频发送弹幕并实现滚动歌词 2023-01-02
- Android MaterialButton使用实例详解(告别shape、selector) 2023-06-16
- iOS 对当前webView进行截屏的方法 2023-03-01
- Android实现轮询的三种方式 2023-02-17
- Android studio实现动态背景页面 2023-05-23
- 详解flutter engine 那些没被释放的东西 2022-12-04
