您现在的位置是:首页 > 文章详情

04.自定义View(SlidingView仿QQ侧滑)

日期:2018-03-27点击:352

感谢红橙Darren博主

布局文件中

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context="com.app.rzm.test.TestSlidingViewActivity"> <com.rzm.commonlibrary.views.SlidingView app:menuPaddingRight="100dp" app:menuParallax="true" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:background="#ffffff" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:text="我在侧边位置" android:textSize="50sp" android:layout_height="match_parent" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:background="@color/transparent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:text="我在主版位置" android:textSize="50sp" android:layout_height="match_parent" /> </LinearLayout> </LinearLayout> </com.rzm.commonlibrary.views.SlidingView> </LinearLayout> 
package com.rzm.commonlibrary.views; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ImageView; import com.rzm.commonlibrary.R; import com.rzm.commonlibrary.utils.LogUtils; /** * Created by renzhenming on 2018/3/28. * * SlidingView继承自HorizontalScrollView,所以在布局中使用的时候,需要设置一个唯一的子View,然后 * 往这个子 view中添加侧边栏和主栏 */ public class SlidingView extends HorizontalScrollView{ private final String TAG = getClass().getSimpleName(); //侧滑菜单的宽度 private final int mMenuWidth; private final Context mContext; //默认的侧边栏滑出最大位置距离右边屏幕的距离 private float mMenuPaddingRight = 100; //侧边菜单布局 private View mMenuView; //主页内容布局,包括用户的contentView和我们添加的阴影效果 private ViewGroup mContentView; //侧边栏menu是否打开 private boolean mMenuOpened; //设置抽屉模式 private boolean mParallaxMode; //手势监听器 private GestureDetector mGestureDetector; //快速滑动打开收起侧边栏的敏感指数,越大敏感度越小,约不容易打开关闭 //不能过大也能过小, private float mSensitivity = 1000; //设置阴影 private ImageView mShadowIv; //视差模式下,默认的侧边栏缩进的距离相对于侧边栏宽度的比例 private float mTransitionPercent = 0.8f; //阴影透明度能达到的最深颜色值 private String mAlphaColor="#99000000"; public SlidingView(Context context) { this(context,null); } public SlidingView(Context context, AttributeSet attrs) { this(context, attrs,-1); } public SlidingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SlidingView); mMenuPaddingRight = typedArray.getDimension(R.styleable.SlidingView_menuPaddingRight, dp2px((int) mMenuPaddingRight)); mParallaxMode = typedArray.getBoolean(R.styleable.SlidingView_menuParallax, mParallaxMode); //侧边栏的宽度 mMenuWidth = (int) (getScreenWidth() - mMenuPaddingRight); typedArray.recycle(); mGestureDetector = new GestureDetector(context, new GestureListener()); } @Override public boolean onTouchEvent(MotionEvent ev) { //如果需要GestureDetector处理,则由其处理 if (mGestureDetector.onTouchEvent(ev)){ return mGestureDetector.onTouchEvent(ev); } switch (ev.getAction()){ case MotionEvent.ACTION_UP: //这个位置指的是,当前这个view和手机屏幕左边届交点距离view最左侧的距离,这里最小为0,不会为负 //当侧边栏滑出的过程中,scrollX呈递减的趋势,直到=0 int scrollX = getScrollX(); LogUtils.d(TAG,"scrollX:"+scrollX); if (scrollX > mMenuWidth/2){ //滑出了一部分,但是还没有到宽度的1/2 closeMenu(); }else{ openMenu(); } return false; } return super.onTouchEvent(ev); } /** * 打开侧边栏 */ private void openMenu() { smoothScrollTo(0,0); mMenuOpened = true; } /** * 关闭侧边栏 */ private void closeMenu() { smoothScrollTo(mMenuWidth,0); mMenuOpened = false; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); //默认设置侧滑菜单隐藏 if (changed){ //scrollTo 让当前屏幕左边界滑动到(mMenuWidth,0)这个坐标位置 scrollTo(mMenuWidth, 0); } } @Override protected void onFinishInflate() { super.onFinishInflate(); //获取根view ViewGroup rootView = (ViewGroup) getChildAt(0); int childCount = rootView.getChildCount(); if (childCount > 2){ throw new IllegalStateException("you should add two child view at most"); } //获取两个布局 mMenuView = rootView.getChildAt(0); //给内容添加阴影效果 mContentView = new FrameLayout(mContext); ViewGroup.LayoutParams contentParams = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT); mContentView.setLayoutParams(contentParams); //获取原来的内容布局,并把原来的内容布局从LinearLayout中异常 View oldContentView = rootView.getChildAt(1); rootView.removeView(oldContentView); //把原来的内容View 和 阴影加到我们新创建的内容布局中 mContentView.addView(oldContentView); //创建阴影 mShadowIv = new ImageView(mContext); mShadowIv.setBackgroundColor(Color.parseColor(mAlphaColor)); mContentView.addView(mShadowIv); //把包含阴影的新的内容View 添加到 LinearLayout中 rootView.addView(mContentView); //设置二者宽度 mMenuView.getLayoutParams().width = mMenuWidth; mContentView.getLayoutParams().width = getScreenWidth(); } private float dp2px(int dp){ return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics()); } /** * 屏幕宽度 * @return */ public int getScreenWidth(){ Resources resources = getResources(); DisplayMetrics metrics = resources.getDisplayMetrics(); return metrics.widthPixels; } private class GestureListener extends GestureDetector.SimpleOnGestureListener{ // 处理手势快速滑动 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { //velocityX,velocityY都是朝坐标系正方向滑动为正,负方向为负,表示正方向上单位时间的速度 //velocityX为正,表示单位时间内, LogUtils.d(TAG,"velocityX:"+velocityX+",velocityY:"+velocityY); if (mMenuOpened){ if (velocityX < -mSensitivity){ toggleMenu(); return true; } }else{ if (velocityX>mSensitivity){ toggleMenu(); return true; } } return super.onFling(e1, e2, velocityX, velocityY); } } /** * 切换菜单的状态 */ private void toggleMenu() { if(mMenuOpened){ closeMenu(); LogUtils.d(TAG,"close"); }else{ openMenu(); LogUtils.d(TAG,"open"); } } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); // l 是 当前滚动的x距离 指的是当前view和屏幕左侧边界相交点距离view最左侧的距离 LogUtils.e(TAG,"onScrollChanged:l===="+l); if (mParallaxMode) { //在onLayout中,默认会将这个SlidingView向左移动一个侧边栏宽度 //这个时候onScrollChanged会被调用,这时候会执行这行代码,将侧边栏向x轴正方向移动一定比例的l宽度,实际上 //也此时,侧边栏已经被放在了主也contentView的下边,此时,滑动contentView的时候,会达到一种视觉差异效果 mMenuView.setTranslationX(l * mTransitionPercent); } //给内容添加阴影效果 - 计算梯度值 float gradientValue = l * 1f / mMenuWidth; LogUtils.e(TAG,"gradientValue:"+gradientValue); //这是 1 - 0 变化的值 //给内容添加阴影效果 - 给阴影的View指定透明度 0 - 1 变化的值 float shadowAlpha = 1 - gradientValue; LogUtils.e(TAG,"shadowAlpha:"+shadowAlpha); mShadowIv.setAlpha(shadowAlpha); } } 
原文链接:https://yq.aliyun.com/articles/657379
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章