Android实现侧滑recycleView+CardVeiw卡片阴影效果

  • 关于
    • 效果图
    • 第一步,定义基本SlideRecyclerView
    • 基本使用
    • cardView使用
    • 菜单+cardView滑出无边距

关于

  本篇主要实现侧滑菜单栏+卡片布局+无间距效果

效果图

  普通的侧滑删除(这不是本篇重点)

  主题卡片阴影的侧滑删除(间隙效果)

  主题卡片阴影的侧滑删除无间距效果

第一步,定义基本SlideRecyclerView

  定义侧滑删除的recycleView,网上一搜一大堆,这里就不做讲解了。基本上就是通过VelocityTracker判断是否有x坐标的移动,有则进行拦截处理事件。

class SlideRecyclerView : RecyclerView {/**滑动的itemView */private var mMoveView: ViewGroup? = null/**itemView中菜单控件宽度 */private var mMenuWidth = 0private var mVelocity: VelocityTracker? = null/**触碰时的首个横坐标 */private var mFirstX = 0/**触碰时的首个纵坐标 */private var mFirstY = 0/**触碰末次的横坐标 */private var mLastX = 0/**最小滑动距离 */private var mTouchSlop = 0private var mScroller: Scroller? = null/**是否正在水平滑动 */private var mMoving = false/**是否由onInterceptTouchEvent()方法拦截 */private var mIntercepted = falseconstructor(context: Context?) : super(context!!) {init()}constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {init()}constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context!!, attrs, defStyle) {init()}private fun init() {mTouchSlop = ViewConfiguration.get(context).scaledTouchSlopmScroller = Scroller(context)}override fun onInterceptTouchEvent(e: MotionEvent): Boolean {val x = e.x.toInt()val y = e.y.toInt()addVelocityEvent(e)when (e.action) {MotionEvent.ACTION_DOWN -> {//若Scroller处于动画中,则终止动画if (!mScroller!!.isFinished) {mScroller!!.abortAnimation()}mFirstX = xmFirstY = ymLastX = x//获取点击区域所在的itemViewval view = findChildViewUnder(x.toFloat(), y.toFloat()) as ViewGroup?//在点击区域以外的itemView开着菜单,则关闭菜单并拦截该次触碰事件if (mMoveView != null && view !== mMoveView && mMoveView!!.scrollX != 0) {closeMenu()mIntercepted = truereturn true}mMoveView = view//获取itemView中菜单的宽度(规定itemView中为两个子View)mMenuWidth = if (mMoveView != null && mMoveView!!.childCount == 2) {mMoveView!!.getChildAt(1).width} else {-1}}MotionEvent.ACTION_MOVE -> {mVelocity!!.computeCurrentVelocity(1000)val velocityX = Math.abs(mVelocity!!.xVelocity).toInt()val velocityY = Math.abs(mVelocity!!.yVelocity).toInt()val moveX = Math.abs(x - mFirstX)val moveY = Math.abs(y - mFirstY)//满足如下条件其一则判定为水平滑动://1、水平速度大于竖直速度,且水平速度大于最小速度//2、水平位移大于竖直位移,且大于最小移动距离//必需条件:itemView菜单栏宽度大于0,且recyclerView处于静止状态(即并不在竖直滑动)val isHorizontalMove =(Math.abs(velocityX) >= MINIMUM_VELOCITY && velocityX > velocityY || moveX > moveY&& moveX > mTouchSlop) && mMenuWidth > 0 && scrollState == 0if (isHorizontalMove) {mIntercepted = truereturn true}}MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {releaseVelocity()//itemView以及其子view触发点击事件,菜单未关闭则直接关闭closeMenuNow()}else -> {}}return super.onInterceptTouchEvent(e)}override fun onTouchEvent(e: MotionEvent): Boolean {val x = e.x.toInt()val y = e.y.toInt()addVelocityEvent(e)when (e.action) {MotionEvent.ACTION_DOWN ->                 //若是通过onInterceptTouchEvent()方法ACTION_DOWN拦截而来的,则丢弃此次事件if (mIntercepted) {mIntercepted = falsereturn false}MotionEvent.ACTION_MOVE -> {mVelocity!!.computeCurrentVelocity(1000)val velocityX = Math.abs(mVelocity!!.xVelocity).toInt()val velocityY = Math.abs(mVelocity!!.yVelocity).toInt()val moveX = Math.abs(x - mFirstX)val moveY = Math.abs(y - mFirstY)val isHorizontalMove =mIntercepted || mMoving || (Math.abs(velocityX) >= MINIMUM_VELOCITY && velocityX > velocityY|| moveX > moveY && moveX > mTouchSlop) && mMenuWidth > 0 && scrollState == 0if (isHorizontalMove) {val dx = mLastX - x//让itemView在规定区域随手指移动if (mMoveView!!.scrollX + dx in 0..mMenuWidth) {mMoveView!!.scrollBy(dx, 0)}mLastX = x//设置正处于水平滑动状态mMoving = truemIntercepted = falsereturn true}}MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {if (mMoving) {mMoving = falsemVelocity!!.computeCurrentVelocity(1000)val scrollX = mMoveView!!.scrollX//若速度大于正方向最小速度,则关闭菜单栏;若速度小于反方向最小速度,则打开菜单栏//若速度没到判断条件,则对菜单显示的宽度进行判断打开/关闭菜单if (mVelocity!!.xVelocity >= MINIMUM_VELOCITY) {mScroller!!.startScroll(scrollX, 0, -scrollX, 0, Math.abs(scrollX))} else if (mVelocity!!.xVelocity < -MINIMUM_VELOCITY) {val dx = mMenuWidth - scrollXmScroller!!.startScroll(scrollX, 0, dx, 0, Math.abs(dx))} else if (scrollX > mMenuWidth / 2) {val dx = mMenuWidth - scrollXmScroller!!.startScroll(scrollX, 0, dx, 0, Math.abs(dx))} else {mScroller!!.startScroll(scrollX, 0, -scrollX, 0, Math.abs(scrollX))}invalidate()} else if (mMoveView != null && mMoveView!!.scrollX != 0) {//若不是水平滑动状态,菜单栏开着则关闭closeMenu()}releaseVelocity()}else -> {}}return super.onTouchEvent(e)}override fun computeScroll() {if (mScroller!!.computeScrollOffset()) {if (isInWindow(mMoveView)) {mMoveView!!.scrollTo(mScroller!!.currX, 0)invalidate()} else {//若处于动画的itemView滑出屏幕,则终止动画,并让其到达结束点位置mScroller!!.abortAnimation()mMoveView!!.scrollTo(mScroller!!.finalX, 0)}}}/*** 使用Scroller关闭菜单栏*/fun closeMenu() {mScroller!!.startScroll(mMoveView!!.scrollX, 0, -mMoveView!!.scrollX, 0, 300)invalidate()}/*** 即刻关闭菜单栏*/fun closeMenuNow() {if (mMoveView != null && mMoveView!!.scrollX != 0) {mMoveView!!.scrollTo(0, 0)}}/*** 获取VelocityTracker实例,并为其添加事件* @param e 触碰事件*/private fun addVelocityEvent(e: MotionEvent) {if (mVelocity == null) {mVelocity = VelocityTracker.obtain()}mVelocity!!.addMovement(e)}/*** 释放VelocityTracker*/private fun releaseVelocity() {if (mVelocity != null) {mVelocity!!.clear()mVelocity!!.recycle()mVelocity = null}}/*** 判断该itemView是否显示在屏幕内* @param view itemView* @return isInWindow*/private fun isInWindow(view: View?): Boolean {if (layoutManager is LinearLayoutManager) {val manager = layoutManager as LinearLayoutManager?val firstPosition = manager!!.findFirstVisibleItemPosition()val lastPosition = manager.findLastVisibleItemPosition()val currentPosition = manager.getPosition(view!!)return currentPosition in firstPosition..lastPosition}return true}companion object {/**最小速度 */private const val MINIMUM_VELOCITY = 500}
}

基本使用

  在布局代码中添加引用,其他的使用和recycleView定义一样:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="#FFFFFF"tools:context=".RecycleViewShowActivity"><Viewandroid:id="@+id/home_title_bg"android:layout_width="match_parent"android:layout_height="75dp"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintTop_toTopOf="parent"android:layout_marginTop="@dimen/dp_25"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"android:textAllCaps="true"android:textColor="#333333"android:textSize="18sp"android:textStyle="bold" /><com.tobeyr1.app.SlideRecyclerViewandroid:id="@+id/rv_show"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toBottomOf="@id/tv_title"/></androidx.constraintlayout.widget.ConstraintLayout>

  添加布局item_inbox_card_list_vertical:

<?xml version="1.0" encoding="UTF-8" ?>
<!--父布局要是LinearLayout-->
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="116dp"android:orientation="horizontal"android:layout_marginTop="16dp"xmlns:app="http://schemas.android.com/apk/res-auto"><!--需要两个子菜单--><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/layout_content"android:layout_width="match_parent"android:background="#BDDDFF"android:layout_height="match_parent"><TextViewandroid:id="@+id/tv_inbox_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="18sp"android:textColor="#333333"android:text="RecycleView+CardView"android:maxLines="1"android:ellipsize="end"app:layout_constraintTop_toTopOf="@id/layout_content"app:layout_constraintBottom_toBottomOf="@id/layout_content"app:layout_constraintStart_toStartOf="@id/layout_content"app:layout_constraintEnd_toEndOf="@id/layout_content"/></androidx.constraintlayout.widget.ConstraintLayout><!--菜单栏部分--><LinearLayoutandroid:layout_width="@dimen/dp_74"android:layout_height="match_parent"android:layout_gravity="center_vertical"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_Delete"android:layout_width="@dimen/dp_74"android:layout_height="match_parent"android:background="#ccf44336"android:text="Delete"android:gravity="center_horizontal"android:textSize="10sp"android:paddingTop="@dimen/dp_20"android:layout_gravity="center"android:textColor="#FFFFFF"app:drawableTopCompat="@drawable/ic_game_list_delete" /></LinearLayout></androidx.appcompat.widget.LinearLayoutCompat>

cardView使用

  修改页面布局,cardView不能设置宽高match_parent,否则没有阴影效果,设置好cardView的margin边距之后,它的父布局宽高一定大于cardview本身大小,以便阴影可以被绘制出来。

<?xml version="1.0" encoding="UTF-8" ?>
<!--父布局要是LinearLayout-->
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="116dp"android:orientation="horizontal"android:layout_marginTop="16dp"xmlns:app="http://schemas.android.com/apk/res-auto"><!--需要两个子菜单--><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="@dimen/dp_116"><androidx.cardview.widget.CardViewandroid:layout_width="match_parent"android:layout_height="@dimen/dp_104"app:cardElevation="@dimen/dp_3"android:layout_marginStart="@dimen/dp_16"android:layout_marginEnd="@dimen/dp_16"android:layout_marginTop="@dimen/dp_6"android:layout_marginBottom="@dimen/dp_6"app:layout_constraintBottom_toBottomOf="parent"app:cardBackgroundColor="#BDDDFF"><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/layout_content"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/tv_inbox_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="18sp"android:textColor="#333333"android:text="RecycleView+CardView"android:maxLines="1"android:ellipsize="end"app:layout_constraintTop_toTopOf="@id/layout_content"app:layout_constraintBottom_toBottomOf="@id/layout_content"app:layout_constraintStart_toStartOf="@id/layout_content"app:layout_constraintEnd_toEndOf="@id/layout_content"/></androidx.constraintlayout.widget.ConstraintLayout></androidx.cardview.widget.CardView></androidx.constraintlayout.widget.ConstraintLayout><!--菜单栏部分--><LinearLayoutandroid:layout_width="@dimen/dp_74"android:layout_height="@dimen/dp_105"android:layout_gravity="center_vertical"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_Delete"android:layout_width="@dimen/dp_74"android:layout_height="match_parent"android:background="#ccf44336"android:text="Delete"android:gravity="center_horizontal"android:textSize="10sp"android:paddingTop="@dimen/dp_20"android:layout_gravity="center"android:textColor="#FFFFFF"app:drawableTopCompat="@drawable/ic_game_list_delete" /></LinearLayout></androidx.appcompat.widget.LinearLayoutCompat>

菜单+cardView滑出无边距

class SlideRecyclerView : RecyclerView {/**滑动的itemView */private var mMoveView: ViewGroup? = null/**itemView中菜单控件宽度 */private var mMenuWidth = 0private var mVelocity: VelocityTracker? = null/**触碰时的首个横坐标 */private var mFirstX = 0/**触碰时的首个纵坐标 */private var mFirstY = 0/**触碰末次的横坐标 */private var mLastX = 0/**最小滑动距离 */private var mTouchSlop = 0private var mScroller: Scroller? = nullprivate var group: ViewGroup? = null //主布局容器/**是否正在水平滑动 */private var mMoving = false/**是否由onInterceptTouchEvent()方法拦截 */private var mIntercepted = falseconstructor(context: Context?) : super(context!!) {init()}constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {init()}constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context!!, attrs, defStyle) {init()}private fun init() {mTouchSlop = ViewConfiguration.get(context).scaledTouchSlopmScroller = Scroller(context)}override fun onInterceptTouchEvent(e: MotionEvent): Boolean {val x = e.x.toInt()val y = e.y.toInt()addVelocityEvent(e)when (e.action) {MotionEvent.ACTION_DOWN -> {//若Scroller处于动画中,则终止动画if (!mScroller!!.isFinished) {mScroller!!.abortAnimation()}mFirstX = xmFirstY = ymLastX = x//获取点击区域所在的itemViewval view = findChildViewUnder(x.toFloat(), y.toFloat()) as ViewGroup?//在点击区域以外的itemView开着菜单,则关闭菜单并拦截该次触碰事件if (mMoveView != null && view !== mMoveView && mMoveView!!.scrollX != 0) {closeMenu()mIntercepted = truereturn true}mMoveView = view//拿到主布局if (mMoveView?.getChildAt(0) != null && mMoveView!!.childCount == 2) group =mMoveView!!.getChildAt(0) as ViewGroup//获取itemView中菜单的宽度(规定itemView中为两个子View)mMenuWidth = if (mMoveView != null && mMoveView!!.childCount == 2) {mMoveView!!.getChildAt(1).width} else {-1}}MotionEvent.ACTION_MOVE -> {mVelocity!!.computeCurrentVelocity(1000)val velocityX = Math.abs(mVelocity!!.xVelocity).toInt()val velocityY = Math.abs(mVelocity!!.yVelocity).toInt()val moveX = Math.abs(x - mFirstX)val moveY = Math.abs(y - mFirstY)//满足如下条件其一则判定为水平滑动://1、水平速度大于竖直速度,且水平速度大于最小速度//2、水平位移大于竖直位移,且大于最小移动距离//必需条件:itemView菜单栏宽度大于0,且recyclerView处于静止状态(即并不在竖直滑动)val isHorizontalMove =(Math.abs(velocityX) >= MINIMUM_VELOCITY && velocityX > velocityY || moveX > moveY&& moveX > mTouchSlop) && mMenuWidth > 0 && scrollState == 0if (isHorizontalMove) {mIntercepted = truereturn true}}MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {setCardViewStatus(false)releaseVelocity()//itemView以及其子view触发点击事件,菜单未关闭则直接关闭closeMenuNow()}else -> {}}return super.onInterceptTouchEvent(e)}override fun onTouchEvent(e: MotionEvent): Boolean {val x = e.x.toInt()val y = e.y.toInt()addVelocityEvent(e)when (e.action) {MotionEvent.ACTION_DOWN ->                 //若是通过onInterceptTouchEvent()方法ACTION_DOWN拦截而来的,则丢弃此次事件if (mIntercepted) {mIntercepted = falseif (!mMoving) setCardViewStatus(false)return false}MotionEvent.ACTION_MOVE -> {mVelocity!!.computeCurrentVelocity(1000)val velocityX = Math.abs(mVelocity!!.xVelocity).toInt()val velocityY = Math.abs(mVelocity!!.yVelocity).toInt()val moveX = Math.abs(x - mFirstX)val moveY = Math.abs(y - mFirstY)val isHorizontalMove =mIntercepted || mMoving || (Math.abs(velocityX) >= MINIMUM_VELOCITY && velocityX > velocityY|| moveX > moveY && moveX > mTouchSlop) && mMenuWidth > 0 && scrollState == 0if (isHorizontalMove) {val dx = mLastX - x//让itemView在规定区域随手指移动if (mMoveView!!.scrollX + dx in 0..mMenuWidth) {mMoveView!!.scrollBy(dx, 0)}setCardViewStatus(true)mLastX = x//设置正处于水平滑动状态mMoving = truemIntercepted = falsereturn true}}MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {if (mMoving) {mMoving = falsemVelocity!!.computeCurrentVelocity(1000)val scrollX = mMoveView!!.scrollX//若速度大于正方向最小速度,则关闭菜单栏;若速度小于反方向最小速度,则打开菜单栏//若速度没到判断条件,则对菜单显示的宽度进行判断打开/关闭菜单if (mVelocity!!.xVelocity >= MINIMUM_VELOCITY) {mScroller!!.startScroll(scrollX, 0, -scrollX, 0, Math.abs(scrollX))setCardViewStatus(false)} else if (mVelocity!!.xVelocity < -MINIMUM_VELOCITY) {val dx = mMenuWidth - scrollXmScroller!!.startScroll(scrollX, 0, dx, 0, Math.abs(dx))setCardViewStatus(true)} else if (scrollX > mMenuWidth / 2) {val dx = mMenuWidth - scrollXmScroller!!.startScroll(scrollX, 0, dx, 0, Math.abs(dx))setCardViewStatus(true)} else {mScroller!!.startScroll(scrollX, 0, -scrollX, 0, Math.abs(scrollX))setCardViewStatus(false)}invalidate()} else if (mMoveView != null && mMoveView!!.scrollX != 0) {//若不是水平滑动状态,菜单栏开着则关闭closeMenu()}releaseVelocity()}else -> {}}return super.onTouchEvent(e)}private fun setCardViewStatus(isOpen: Boolean) {//item滑动action的状态,根据菜单是否关闭等修改cardview的边距,同理其他内部控件一样group?.forEach {if (it is CardView) {val lp: ConstraintLayout.LayoutParams =it.layoutParams as ConstraintLayout.LayoutParamslp.rightMargin = if (isOpen) 0 else PxUtils.dpToPx(16, it.context)it.layoutParams = lp}}}override fun computeScroll() {if (mScroller!!.computeScrollOffset()) {if (isInWindow(mMoveView)) {mMoveView!!.scrollTo(mScroller!!.currX, 0)invalidate()} else {//若处于动画的itemView滑出屏幕,则终止动画,并让其到达结束点位置mScroller!!.abortAnimation()mMoveView!!.scrollTo(mScroller!!.finalX, 0)}}}/*** 使用Scroller关闭菜单栏*/fun closeMenu() {mScroller!!.startScroll(mMoveView!!.scrollX, 0, -mMoveView!!.scrollX, 0, 300)invalidate()}/*** 即刻关闭菜单栏*/fun closeMenuNow() {if (mMoveView != null && mMoveView!!.scrollX != 0) {mMoveView!!.scrollTo(0, 0)}}/*** 获取VelocityTracker实例,并为其添加事件* @param e 触碰事件*/private fun addVelocityEvent(e: MotionEvent) {if (mVelocity == null) {mVelocity = VelocityTracker.obtain()}mVelocity!!.addMovement(e)}/*** 释放VelocityTracker*/private fun releaseVelocity() {if (mVelocity != null) {mVelocity!!.clear()mVelocity!!.recycle()mVelocity = null}}/*** 判断该itemView是否显示在屏幕内* @param view itemView* @return isInWindow*/private fun isInWindow(view: View?): Boolean {if (layoutManager is LinearLayoutManager) {val manager = layoutManager as LinearLayoutManager?val firstPosition = manager!!.findFirstVisibleItemPosition()val lastPosition = manager.findLastVisibleItemPosition()val currentPosition = manager.getPosition(view!!)return currentPosition in firstPosition..lastPosition}return true}companion object {/**最小速度 */private const val MINIMUM_VELOCITY = 500}
}

  本篇文章到此结束,有问题欢迎批评指正

Android实现侧滑recycleView+CardVeiw卡片阴影效果相关推荐

  1. 【Android】侧滑按钮

    [Android]侧滑按钮 效果视频 导入闭包 将以下语句倒入目录下build.gradle文件内 implementation 'com.github.WangcWj:WeSwipe:1.0.2'i ...

  2. Android ListView侧滑item,仿QQ删除效果

    尊重原创,转载请注明(http://blog.csdn.net/aoshiwenrou/article/details/42971193) 最近的项目需求有一条是要实现仿QQ的侧滑删除效果,网上搜到了 ...

  3. Android之去掉RecycleView和NestedScrollView边缘效果

    1 问题 使用RecycleView和NestedScrollView的时候,滑倒顶部或者底部,会有边缘效果,就像水温波一样,现在需求去掉 2 解决办法 在RecycleView和NestedScro ...

  4. android 点击侧滑代码,代码分析Android实现侧滑菜单

    Android 侧滑菜单的实现,参考网上的代码,实现侧滑菜单.最重要的是这个动画类UgcAnimations,如何使用动画类来侧滑的封装FlipperLayout. 1.实现效果 2.动画类UgcAn ...

  5. android 抽屉侧滑冲突,利用DrawerLayout和触摸事件分发实现抽屉侧滑效果

    本文实例为大家分享了DrawerLayout和触摸事件分发实现抽屉侧滑效果的具体代码,供大家参考,具体内容如下 效果展示 还是看代码实在,直接上菜了. 1.MainActivity的代码: publi ...

  6. Android 5.0+(RecycleView、CardView、Palette)

    2019独角兽企业重金招聘Python工程师标准>>> Android L 开发者预览支持库提供两个新的Widgets,RecyclerView和CardView.使用这两个Wid ...

  7. android自定义侧滑菜单slidmenu

    实现上主要就是一个自定义的MySlidView,在这个MySlidView里边去加载两个你要显示的View(mMenuView, mSlidView),即一个是滑动之后,左侧的mSlidView,另一 ...

  8. android自定义侧滑菜单代码,原生Android 侧滑菜单实践(部分)

    此为第一个制作侧滑菜单的实践 . 此部分仅仅为部分实践: 仅缺menu的字符串布局,以及需要修改的MainActivity.java文件,也是需要主要修改的地方. 从使用MD设计-进行侧滑菜单的制作( ...

  9. android实现左拉菜单,Android原生侧滑控件DrawerLayout使用方法详解

    在android的v4包中有一个控件 Drawerlayout,主要实现了左拉和右拉菜单,类似于之前的"抽屉"功能,此控件使用简单,效果很柔和,操作起来体验非常好,下面是我实现的一 ...

  10. android 高仿 探探卡片滑动,Android自定义View仿探探卡片滑动效果

    Android自定义View仿探探卡片滑动这种效果网上有很多人已经讲解了实现思路,大多都用的是RecyclerView来实现的,但是我们今天来换一种实现思路,只用一个自定义的ViewGroup来搞定这 ...

最新文章

  1. EJS 什么是EJS后缀文件 EJS怎么用
  2. 修改can接口波特率_CAN总线分析仪使用
  3. SAP 错误日志的调查
  4. UVA - 1415 Gauss Prime(高斯素数)
  5. Android项目开发新版本需要注意的事项
  6. 关于Consul的几个问题
  7. Django使用Python操作数据库 --Django 1.8.2 文档(中文)部分笔记
  8. 2019-06-11_Python中文编码
  9. Android LinkedList的部分源码解析
  10. 服务器如果选用CPU
  11. 【高并发解决方案】高并发解决方案汇总
  12. ASP模式“救星降临”?(转)
  13. 反编译apktool
  14. AI量化交易=交易接口+L2行情数据接口+A股策略
  15. ios 应用跳转商店
  16. HW算法题:判断字符串子序列
  17. explorer.exe 应用程序错误 应用程序发生异常 未知软件异常 (0xc0000417),位置为 0x100170e9
  18. python xlutils模块安装_python接口测试,第三方包xlrd和xlutils,怎么安装
  19. java pdf去水印_java使用spire.pdf去除水印
  20. 笔记本有时候能开机 有时候开不了

热门文章

  1. python爬虫:xpath解析
  2. Mac自带浏览器safari怎么打开开发者选项
  3. GitHub怎么搜索项目
  4. 台式计算机的打印机端口,台式电脑怎么连接网络打印机
  5. 机器学习 损失函数 Loss function
  6. Snipaste--截屏--贴图
  7. 微信下载app需要点击右上角在浏览器中打开下载的解决办法
  8. 《北国之春》--华为总裁:任正非
  9. Parallels Desktop 13 for Mac 中文正式版下载 – 优秀的虚拟机
  10. 在线hash密码破解网站列表