最近在投简历的时候发现智联招聘的公司详情页设计的很有意思,虽然很简单,但是也忍不住仿一下,
智联的效果
仿的效果(基本效果一致)
效果需求分析:
1、刚进入界面时,“在招职位”布局在底部露头,并距离屏幕左边一半屏幕宽度的距离。
2、当详情滑动到最底部,然后再向上滑动时,展开“在招职位”布局。
3、“在招职位”布局支持手势拖动,向上时布局距离屏幕左边越来越近(最终距离屏幕左边距离为0),向下时布局距离越来越远(最终是屏幕的宽度的一半)。
根据上面的分析,主要的功能其实就是这个“在招职位”布局的收起和展开,默认收起,然后手势控制展开。说到这里其实我们就知道如何实现了,那就是behavior,它默认已经给我们处理了收起展开状态及拖动操作,我们只需要监听拖动和状态来设置布局的位置变化就可以了。开干~
为了省事底部布局我就直接截图放到布局了
###XML
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout 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" android:background="#0099cc"> <androidx.core.widget.NestedScrollView android:id="@+id/scrollview" android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" app:srcCompat="@drawable/icon_detail_zhilian" /> </androidx.core.widget.NestedScrollView> <androidx.appcompat.widget.LinearLayoutCompat android:id="@+id/bottom_sheet" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingTop="50dp" android:visibility="visible" app:behavior_hideable="true" app:behavior_peekHeight="110dp" app:layout_behavior="@string/bottom_sheet_behavior" tools:ignore="MissingPrefix"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="60dp" android:background="@drawable/shape_header"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/layout_bottom_sheet" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:gravity="center" android:orientation="vertical" android:text="在招职位-54个" android:textColor="@android:color/black" android:textSize="14sp" android:layout_margin="24dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/drag" android:layout_width="16dp" android:layout_height="16dp" android:layout_margin="8dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@mipmap/ic_launcher_round" /> </androidx.constraintlayout.widget.ConstraintLayout> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="wrap_content" /> </androidx.appcompat.widget.LinearLayoutCompat> </androidx.coordinatorlayout.widget.CoordinatorLayout>
###Activity
package com.study.fangdemo.zhilian import android.os.Bundle import android.view.MotionEvent import android.view.View import android.view.ViewConfiguration import android.view.ViewGroup.MarginLayoutParams import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior.* import com.study.fangdemo.databinding.ActivityMainBinding import com.study.fangdemo.utils.RecyclerDataUtils class ZhiLianActivity : AppCompatActivity() { private var binding: ActivityMainBinding? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding?.root) initView() initListener() } private fun initListener() { val behavior = from(binding!!.bottomSheet) behavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { //左边图标显示 binding?.drag?.isVisible = true when (newState) { STATE_DRAGGING -> {} STATE_SETTLING -> {} STATE_EXPANDED -> { //展开状态时隐藏左边图标 binding?.drag?.isVisible = false } STATE_COLLAPSED -> {} STATE_HIDDEN -> {} STATE_HALF_EXPANDED -> {} } } override fun onSlide(bottomSheet: View, slideOffset: Float) { val width = windowManager.defaultDisplay.width val margin = ((0.5 - slideOffset / 2) * width).toInt() margin(bottomSheet, margin) } }) //详情滑动到底部 再往上滑动时展开 binding?.scrollview?.setOnTouchListener(object : View.OnTouchListener { var startX: Float = 0.0f var startY: Float = 0.0f var offsetX: Float = 0.0f var offsetY: Float = 0.0f var touchSlop = ViewConfiguration.get(baseContext).scaledTouchSlop override fun onTouch(view: View?, event: MotionEvent?): Boolean { when (event?.action) { MotionEvent.ACTION_DOWN -> { startX = event.x startY = event.y } MotionEvent.ACTION_UP -> { offsetX = event.x - startX offsetY = event.y - startY if (Math.abs(offsetX) > Math.abs(offsetY)) { // left if (offsetX < -touchSlop) { } // right else if (offsetX > touchSlop) { } } else { // up if (offsetY < -touchSlop) { if (isScrollViewEnd()) { behavior.state = STATE_EXPANDED } } // down else if (offsetY > touchSlop) { } } } } return false } }) } /** * NestedScrollView 是否滚动到底部 */ private fun isScrollViewEnd(): Boolean { binding?.apply { var scrollY = scrollview?.scrollY var onlyChild = scrollview?.getChildAt(0) if (onlyChild?.height!! <= (scrollY!! + scrollview?.height!!)) { return true } } return false } private fun initView() { binding?.apply { //设置测试列表数据 RecyclerDataUtils.setRecyclerAdater(baseContext, recyclerview, "测试数据", 30) //设置屏幕宽 bottomSheet?.post { val params = bottomSheet.layoutParams params.width = windowManager.defaultDisplay.width bottomSheet.layoutParams = params } //默认外左边距是屏幕宽度一半 margin(bottomSheet, windowManager.defaultDisplay.width / 2) } } /** * 设置左边Margin */ private fun margin(v: View, l: Int) { if (v.layoutParams is MarginLayoutParams) { val p = v.layoutParams as MarginLayoutParams p.leftMargin = l v.requestLayout() } } }
代码其实还是比较少的,其实主要是通过监听拖动来设置“在招职位”布局距离左边的margin值就可以了,希望能对新入手的同学有点帮助,我也算复习了下。
具体的测试APK可以通过这个链接测试下:
github:https://github.com/yixiaolunhui/FangDemo