日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

Android 仿微信小程序入口動畫

瀏覽:179日期:2022-06-03 16:35:17
目錄效果對比流程分析自定義ViewGroup小程序縮放比例值計算動畫遮罩MainActivity效果對比

微信原版

Android 仿微信小程序入口動畫

仿照效果

Android 仿微信小程序入口動畫

流程分析自定義ViewGroup

整個布局是通過自定義ViewGroup來管理的,在自定義ViewGroup中,子布局一共有兩個,一個是小程序布局,一個是會話列表布局,然后按照上下分別擺放就可以了。

Android 仿微信小程序入口動畫

package com.example.kotlindemo.widget.weixinimport android.content.Contextimport android.content.res.Resourcesimport android.util.AttributeSetimport android.util.Logimport android.view.MotionEventimport android.view.Viewimport android.view.ViewGroupimport androidx.core.view.ViewCompatimport androidx.customview.widget.ViewDragHelperimport com.example.kotlindemo.Rimport java.math.BigDecimalclass WeiXinMainPullViewGroup @JvmOverloads constructor( context: Context?, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ViewGroup(context, attrs, defStyleAttr) { public var viewDragHelper: ViewDragHelper = ViewDragHelper.create(this, 0.5f, DragHandler()); var headerMaskView: WeiXinPullHeaderMaskView? = null var isOpen: Boolean = false; val NAVIGAATION_HEIGHT = 100 init { } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {for (index in 0 until childCount) { if (getChildAt(index) != headerMaskView) {getChildAt(index).layout(l, paddingTop, r, b) }} } override fun computeScroll() {if (viewDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this);} } override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {Log.i('TAG', 'onInterceptTouchEvent: ${ev.action}')MotionEvent.ACTION_MOVEreturn true } override fun onTouchEvent(event: MotionEvent): Boolean {viewDragHelper.processTouchEvent(event)return true } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)measureChildren(widthMeasureSpec, heightMeasureSpec) } fun createMaskView() {if (headerMaskView == null) { headerMaskView = WeiXinPullHeaderMaskView(context, null, 0) addView(headerMaskView)} } inner class DragHandler : ViewDragHelper.Callback() {override fun tryCaptureView(child: View, pointerId: Int): Boolean { return child is WeiXinMainLayout;}override fun onViewDragStateChanged(state: Int) { super.onViewDragStateChanged(state)}/** * 設(shè)置進度,設(shè)置遮罩layout */override fun onViewPositionChanged( changedView: View, left: Int, top: Int, dx: Int, dy: Int) { createMaskView(); var programView = getChildAt(0) 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)) } headerMaskView!!.maxHeight = measuredHeight / 3 headerMaskView!!.layout(0, paddingTop, measuredWidth, top) headerMaskView!!.setProgress(top.toFloat() / ((measuredHeight - (NAVIGAATION_HEIGHT + paddingTop)) / 3) * 100,measuredHeight - (NAVIGAATION_HEIGHT + paddingTop) ) if (top == paddingTop) {isOpen = false } if (top == measuredHeight - NAVIGAATION_HEIGHT) {isOpen = true }}override fun onViewCaptured(capturedChild: View, activePointerId: Int) { super.onViewCaptured(capturedChild, activePointerId) var programView = getChildAt(0) programView.top = paddingTop;}/** * 釋放 */override fun onViewReleased(releasedChild: View, xvel: Float, yvel: Float) { /** * 如果已經(jīng)打開或者釋放后小于屏幕三分之一,回到原位 */ if (isOpen or (releasedChild.top + paddingTop <= measuredHeight / 3)) {viewDragHelper.smoothSlideViewTo(releasedChild, 0, paddingTop);ViewCompat.postInvalidateOnAnimation(this@WeiXinMainPullViewGroup);return } viewDragHelper.smoothSlideViewTo(releasedChild, 0, measuredHeight - NAVIGAATION_HEIGHT); ViewCompat.postInvalidateOnAnimation(this@WeiXinMainPullViewGroup);}override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int { if (top <= paddingTop) {return paddingTop } return (child.top + dy / 1.3).toInt();} }}

還要增加一個用來填充狀態(tài)欄的View,他的高度是動態(tài)獲取的,整體布局是RelativeLayout,因為可以方便的設(shè)置中間View在狀態(tài)下面和在導(dǎo)航欄上面。

class ViewUtils { companion object{@JvmStaticfun 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來完成,當(dāng)拖動會話布局的時候,小程序的布局開始做一個縮放比例動畫,這個縮放值我在這是這樣做的,因為不可能是從0開始,要從一個基礎(chǔ)值開始,這個基礎(chǔ)值就是0.8,那么剩下0.2的縮放值,就是從開始下拉算起,到整體的高度的百分比。

比如屏幕高度是1000,下拉到500的時候,那么這個縮放值就是0.1,在加上基礎(chǔ)值0.8,計算方式如下,整體高度還要減去導(dǎo)航欄的高度。

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)) }

這里就注意細節(jié)了,下拉的時候,小程序布局是通過縮放呈現(xiàn)的,但是上滑關(guān)閉的時,小程序布局是和會話布局同時向上走的。

動畫遮罩

這是比較麻煩的一步,就是繪制進度動畫,也就是那三個圓點。

這個原點有三種狀態(tài),一是出現(xiàn)時從小到大,二是到一定大小后,分離出兩個固定大小的圓,但是這兩個圓比此時中間的要小,并且和下拉進度慢慢向兩邊擴撒,三是中間的圓開始縮小,直到和其余兩個圈同等大小。

這里就要另一波細節(jié)了,當(dāng)還在屏幕的三分之一下拉時,這個頭部遮罩布局整體還是不透明的,但是到屏幕的三分之一時,這個布局的透明度開始從255到0運動。并且到達三分之一的時候,還要振動一下,并且只要振動過了,那么在手指未松開時,再次到達屏幕的三分之一時,不會產(chǎn)生振動。

還有一波細節(jié),狀態(tài)欄由于使用了View填充,所以,從屏幕三份之一后開始,這個View的透明度也要從255-0開始運動。

完整代碼如下。

package com.example.kotlindemo.widget.weixinimport android.content.Contextimport android.graphics.Canvasimport android.graphics.Colorimport android.graphics.Paintimport android.os.VibrationEffectimport android.os.Vibratorimport android.util.AttributeSetimport android.util.Logimport android.view.Viewimport androidx.core.content.ContextCompatimport com.example.kotlindemo.MainActivityimport com.example.kotlindemo.Rclass 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() / maxHeightif (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 Vibratorif (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.Colorimport android.os.Buildimport android.os.Bundleimport android.view.Viewimport android.view.Windowimport androidx.appcompat.app.AppCompatActivityimport androidx.databinding.DataBindingUtilimport com.example.kotlindemo.databinding.ActivityMainBindingimport com.example.kotlindemo.widget.weixin.ChatSessionimport com.example.kotlindemo.widget.weixin.ChatSessionAdapterimport com.example.kotlindemo.widget.weixin.ViewUtilsclass 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.layoutParamslayoutParams.height=ViewUtils.getStatusBarHeight(resources)binding.statusBar.layoutParams=layoutParamsbinding.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_FULLSCREENor 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> <RelativeLayoutandroid: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.WeiXinMainPullViewGroupandroid:paddingTop='40dp' android:layout_above='@+id/navigation' android: android:layout_width='match_parent' android:layout_height='match_parent' > <com.example.kotlindemo.widget.weixin.WeiXinProgramandroid: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'> <LinearLayoutandroid: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.WeiXinMainLayoutandroid: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'> <TextViewandroid: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> <ImageViewandroid:layout_marginRight='45dp'android:scaleType='center'android:layout_centerVertical='true'android:layout_alignParentRight='true'android:src='http://www.b3g6.com/bcjs/@drawable/ic_search'android:layout_width='28dp'android:layout_height='28dp'></ImageView> <ImageViewandroid:layout_marginRight='10dp'android:scaleType='center'android:layout_centerVertical='true'android:layout_alignParentRight='true'android:src='http://www.b3g6.com/bcjs/@drawable/ic_add'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: 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: android:layout_alignParentBottom='true' android:layout_width='match_parent' android:layout_height='60dp'></LinearLayout><View android:background='@color/navigation_color' android: android:layout_width='match_parent' android:layout_height='100dp'></View> </RelativeLayout></layout>

以上就是Android 仿微信小程序入口動畫的詳細內(nèi)容,更多關(guān)于Android 微信小程序入口動畫的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標簽: 微信
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产精品欧美三级在线观看| 国产伦理一区| 嫩草伊人久久精品少妇av杨幂 | 精品国产aⅴ| 欧美日韩精品一区二区三区视频 | 久久久噜噜噜| 天堂日韩电影| 婷婷综合激情| 亚洲三级在线| 免费在线观看一区| 精品一二三区| 久久黄色影院| 蜜臀av一区二区在线免费观看| 午夜亚洲精品| 欧美天堂一区二区| 中文字幕在线免费观看视频| 亚洲一级少妇| 免费人成在线不卡| 国产精品久久久久毛片大屁完整版| 国产精品一区毛片| 久久激情中文| 日本国产欧美| 日韩伦理在线一区| 亚洲综合二区| 国产一区二区久久久久| 日本久久成人网| 午夜在线精品偷拍| 国产伊人久久| 亚洲欧美专区| 蜜桃精品在线| 欧美一级全黄| 国产美女一区| a日韩av网址| 国产午夜久久av| 91久久亚洲| 日韩福利一区| 国产精品网址| 欧美专区18| 99久久夜色精品国产亚洲狼| 青青草伊人久久| 日韩午夜黄色| 麻豆成人综合网| 亚洲精品一级| 九一精品国产| 国产麻豆久久| 日韩不卡一区| 久久精品国产一区二区| 亚洲va久久| 日韩精品一区第一页| 久久久久国产精品一区三寸| 麻豆精品99| 国产免费久久| 91伊人久久| 啪啪亚洲精品| 热久久久久久| 国产精品免费精品自在线观看| 欧美日韩国产免费观看| 99视频精品全部免费在线视频| 日韩综合在线| 成人片免费看| 久久国产电影| 亚洲一级影院| 免费久久99精品国产自在现线| 国产99久久| 鲁大师成人一区二区三区| 亚洲黄页一区| 丝袜a∨在线一区二区三区不卡 | 99riav国产精品| 国产精品美女久久久浪潮软件| 97se综合| 亚洲精品网址| 综合激情婷婷| 国产精品一区二区av交换| 国产精品magnet| 麻豆理论在线观看| 午夜精品一区二区三区国产| 久久中文视频| 日韩精品高清不卡| 欧美精品99| 久久精品青草| 亚洲精品裸体| 久久男人av资源站| 另类av一区二区| 久久不卡日韩美女| 精品久久美女| 亚洲一区二区三区免费在线观看| 视频在线在亚洲| 麻豆免费精品视频| 亚洲性色视频| 国产精品亚洲二区| 激情综合激情| 麻豆成人综合网| 亚洲综合日本| yellow在线观看网址| 亚洲一区二区成人| 国产一区二区三区免费在线 | 国产精品一区二区免费福利视频| 国产一区日韩| 99re国产精品| 高清精品久久| 亚洲精品精选| 激情久久中文字幕| 欧美国产日韩电影| 中文不卡在线| se01亚洲视频 | 亚洲人成网77777色在线播放| 国产高清不卡| 欧美日韩亚洲一区三区| 五月婷婷亚洲| 香蕉成人av| 久久伊人亚洲| 亚洲香蕉久久| 欧美jjzz| 久久精品亚洲人成影院 | 国产亚洲一区二区三区啪| 亚洲一级二级| 午夜精品成人av| 另类欧美日韩国产在线| 日日夜夜免费精品视频| 欧美在线影院| 一区在线免费观看| 欧美成人日韩| 国产拍在线视频| 国产videos久久| 精品一区二区三区中文字幕| 国产亚洲高清在线观看| 最新国产精品久久久| 亚洲综合不卡| 国产亚洲精品自拍| 久久激情网站| 激情五月综合网| 偷拍欧美精品| 免费精品视频最新在线| 中文字幕一区二区三区四区久久| 午夜精品网站| 日本不卡一二三区黄网| 日韩一区二区三区高清在线观看| 欧美日韩精品免费观看视频完整| 午夜电影亚洲| 一本综合精品| 国产亚洲人成a在线v网站| 蜜桃视频一区二区三区在线观看| 爽好多水快深点欧美视频| 国产精品17p| 日韩毛片网站| 国产中文字幕一区二区三区| 精品丝袜久久| 红桃视频国产一区| 日本精品另类| av资源亚洲| 中文字幕一区二区精品区| 国产一精品一av一免费爽爽| 日韩影片在线观看| av日韩中文| 亚洲aa在线| 日本精品在线中文字幕| 日本高清不卡一区二区三区视频| 伊人久久大香线蕉av不卡| 日韩欧美中文在线观看| 久久久久久夜| 日韩**一区毛片| 99久久九九| 国产精品一区二区精品视频观看| 国产在线视频欧美一区| 91精品电影| 国产aⅴ精品一区二区四区| 国产亚洲网站| 里番精品3d一二三区| 亚洲欧美日韩精品一区二区 | 国产另类在线| 久久高清免费观看| 精品国产成人| 日韩激情中文字幕| 午夜精品一区二区三区国产| 国产精品亚洲产品| 综合激情五月婷婷| 激情欧美一区二区三区| 精品国产日韩欧美精品国产欧美日韩一区二区三区 | 久久中文字幕av一区二区不卡| 奇米狠狠一区二区三区| 欧洲激情综合| 日韩在线短视频| 成人一区而且| 久久一区亚洲| 国产精品亚洲欧美日韩一区在线| 久久av在线| 羞羞答答国产精品www一本| 欧美日韩免费看片| 婷婷激情一区| 另类中文字幕国产精品| 岛国av免费在线观看| 国产精品原创| 久久国产毛片| 欧美综合另类| 欧美日韩国产免费观看| 日韩一级欧洲| 亚洲一区成人| 日本v片在线高清不卡在线观看| 亚洲大全视频| 亚洲欧洲日韩|