仿QQ6.0主页面侧滑效果(第二种实现方法)

仿QQ6.0主页面侧滑效果(第二种实现方法),第1张

概述效果展示背景对于这个效果,我之前写过一种实现方法 仿QQ6.0主页面侧滑效果,这种方法跟手性不好,如果复现了的朋友应该能体会到,并且,还得自己处理很多onTouch事件,所以,这篇文章带大家体验一下另外一种实现方法,继承自 HorizontalScrollView实现步骤第一步:创建自定义类packa 效果展示

背景

对于这个效果,我之前写过一种实现方法 仿QQ6.0主页面侧滑效果,这种方法跟手性不好,如果复现了的朋友应该能体会到,并且,还得自己处理很多 ontouch 事件,所以,这篇文章带大家体验一下另外一种实现方法,继承自 horizontalscrollview

实现步骤

第一步:创建自定义类

package com.wust.myhorizontalscrollview;import androID.content.Context;import androID.util.AttributeSet;import androID.Widget.horizontalscrollview;public class mySlIDingMenu extends horizontalscrollview {    public mySlIDingMenu(Context context) {        this(context,null);    }    public mySlIDingMenu(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public mySlIDingMenu(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }}

第二步:引用布局 

<?xml version="1.0" enCoding="utf-8"?><linearLayout 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:orIEntation="horizontal"    tools:context=".MainActivity">    <com.wust.myhorizontalscrollview.mySlIDingMenu        androID:layout_wIDth="match_parent"        androID:layout_height="match_parent">        <TextVIEw            androID:layout_wIDth="match_parent"            androID:layout_height="match_parent"            androID:text="我是菜单"            androID:background="#f00"/>        <TextVIEw            androID:layout_wIDth="match_parent"            androID:layout_height="match_parent"            androID:text="我是内容"            androID:background="#0f0"/>    </com.wust.myhorizontalscrollview.mySlIDingMenu></linearLayout>

如果大家在这一步试图去运行,就会发现报错,如下:

 

大概意思就是说 horizontalscrollview 里面只能包一个布局,所以,我们得把上面的布局文件修改一下,用一个线性布局把他们包起来

<?xml version="1.0" enCoding="utf-8"?><linearLayout 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:orIEntation="horizontal"    tools:context=".MainActivity">    <com.wust.myhorizontalscrollview.mySlIDingMenu        androID:layout_wIDth="match_parent"        androID:layout_height="match_parent">        <linearLayout            androID:layout_wIDth="match_parent"            androID:orIEntation="horizontal"            androID:layout_height="match_parent">            <TextVIEw                androID:layout_wIDth="match_parent"                androID:layout_height="match_parent"                androID:text="我是菜单"                androID:background="#f00"/>            <TextVIEw                androID:layout_wIDth="match_parent"                androID:layout_height="match_parent"                androID:text="我是内容"                androID:background="#0f0"/>                    </linearLayout>    </com.wust.myhorizontalscrollview.mySlIDingMenu></linearLayout>

 第三步:编写逻辑

这个时候当我们运行程序的时候就会发现,我们明明写的 match_parent 可是最后的结果不是铺满的,所以,我们得给我们的自定义组件赋值宽高。在 onMeasure() 方法里??我们不妨来试试

package com.wust.myhorizontalscrollview;import androID.content.Context;import androID.util.AttributeSet;import androID.util.displayMetrics;import androID.vIEw.VIEw;import androID.vIEw.VIEwGroup;import androID.vIEw.WindowManager;import androID.Widget.horizontalscrollview;public class mySlIDingMenu extends horizontalscrollview {    private int mScreenWIDth;    private VIEw mMenu;    private VIEw mContent;    private int mMenuWIDth;    private int mContentWIDth;    private int mScrennHeight;    public mySlIDingMenu(Context context) {        this(context,null);    }    public mySlIDingMenu(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public mySlIDingMenu(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //获取屏幕宽度        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        displayMetrics metrics = new displayMetrics();        wm.getDefaultdisplay().getMetrics(metrics);        mScreenWIDth = metrics.wIDthPixels;        mScrennHeight = metrics.heightPixels;    }    @OverrIDe    protected voID onMeasure(int wIDthMeasureSpec, int heightmeasureSpec) {        super.onMeasure(wIDthMeasureSpec, heightmeasureSpec);        //初始化宽度、高度        int wIDth = 0;        int height = 0;        //获取子代        VIEwGroup ll_child = (VIEwGroup) getChildAt(0);        mMenu = ll_child.getChildAt(0);        mContent = ll_child.getChildAt(1);        //设置菜单 内容的宽度        mMenuWIDth = mMenu.getLayoutParams().wIDth = mScreenWIDth - 400;        mContentWIDth = mContent.getLayoutParams().wIDth = mScreenWIDth;        //设置自定义组件的宽高        wIDth = mMenuWIDth + mContentWIDth;        height = mScrennHeight;        setMeasuredDimension(wIDth,height);    }}

我们发现布局结构的确出来了,但是划不动, 最大的可能就是我们设置宽高的时机不对,通过翻阅资料,我发现我们应该写在布局解析完成这个时间节点

package com.wust.myhorizontalscrollview;import androID.content.Context;import androID.util.AttributeSet;import androID.util.displayMetrics;import androID.vIEw.VIEw;import androID.vIEw.VIEwGroup;import androID.vIEw.WindowManager;import androID.Widget.horizontalscrollview;public class mySlIDingMenu extends horizontalscrollview {    private int mScreenWIDth;    private VIEw mMenu;    private VIEw mContent;    private int mMenuWIDth;    private int mContentWIDth;    private int mScrennHeight;    public mySlIDingMenu(Context context) {        this(context,null);    }    public mySlIDingMenu(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public mySlIDingMenu(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //获取屏幕宽度        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        displayMetrics metrics = new displayMetrics();        wm.getDefaultdisplay().getMetrics(metrics);        mScreenWIDth = metrics.wIDthPixels;        mScrennHeight = metrics.heightPixels;    }    @OverrIDe    protected voID onFinishInflate() {        super.onFinishInflate();        //获取子代        VIEwGroup ll_child = (VIEwGroup) getChildAt(0);        mMenu = ll_child.getChildAt(0);        mContent = ll_child.getChildAt(1);        //设置菜单 内容的宽度        mMenuWIDth = mMenu.getLayoutParams().wIDth = mScreenWIDth - 400;        //设置布局宽度的第二种方法        VIEwGroup.LayoutParams contentLayoutParams = mContent.getLayoutParams();        mContentWIDth = contentLayoutParams.wIDth = mScreenWIDth;        mContent.setLayoutParams(contentLayoutParams);    }}

这个时候,你就会发现屏幕可以滑动了

第四步:优化

经过上面三步,侧滑菜单我们就做完了,下面所讲是为了优化用户体验

优化一:最初渲染页面的时候,菜单栏是关闭的

在这一步中要注意 关闭菜单的时机,即到底写在那个函数里

package com.wust.myhorizontalscrollview;import androID.content.Context;import androID.util.AttributeSet;import androID.util.displayMetrics;import androID.vIEw.VIEw;import androID.vIEw.VIEwGroup;import androID.vIEw.WindowManager;import androID.Widget.horizontalscrollview;public class mySlIDingMenu extends horizontalscrollview {    private int mScreenWIDth;    private VIEw mMenu;    private VIEw mContent;    private int mMenuWIDth;    private int mContentWIDth;    private int mScrennHeight;    public mySlIDingMenu(Context context) {        this(context,null);    }    public mySlIDingMenu(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public mySlIDingMenu(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //获取屏幕宽度        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        displayMetrics metrics = new displayMetrics();        wm.getDefaultdisplay().getMetrics(metrics);        mScreenWIDth = metrics.wIDthPixels;        mScrennHeight = metrics.heightPixels;    }    @OverrIDe    protected voID onFinishInflate() {        super.onFinishInflate();        //获取子代        VIEwGroup ll_child = (VIEwGroup) getChildAt(0);        mMenu = ll_child.getChildAt(0);        mContent = ll_child.getChildAt(1);        //设置菜单 内容的宽度        mMenuWIDth = mMenu.getLayoutParams().wIDth = mScreenWIDth - 400;        //设置布局宽度的第二种方法        VIEwGroup.LayoutParams contentLayoutParams = mContent.getLayoutParams();        mContentWIDth = contentLayoutParams.wIDth = mScreenWIDth;        mContent.setLayoutParams(contentLayoutParams);    }    @OverrIDe    protected voID onLayout(boolean changed, int l, int t, int r, int b) {        super.onLayout(changed, l, t, r, b);        closeMenu();    }    private voID closeMenu(){        smoothScrollTo(mMenuWIDth,0);    }    private voID openMenu(){        smoothScrollTo(0,0);    }}
优化二:判断手指抬起时是否超过菜单宽度一半,超过即打开菜单,没有超过即关闭菜单

在这一步中要区别于我们上讲 仿QQ6.0主页面侧滑效果 中的滑动正负观,在这我就不过多赘述,大家自己动手实践就知道了

@OverrIDe    public boolean ontouchEvent(MotionEvent ev) {        switch(ev.getAction()){            //自己处理 手指抬起事件 所以 return true            case MotionEvent.ACTION_UP:            {                //就是这里要注意,因为最开始 getScrollX() 的值是 mMenuWIDth                if (getScrollX() > mMenuWIDth/2){                    closeMenu();                }else {                    openMenu();                }                return true;            }        }        return super.ontouchEvent(ev);    }
优化三:处理快速滑动手势

在这个里面主要用到了一个类 GestureDetector

public mySlIDingMenu(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //获取屏幕宽度        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        displayMetrics metrics = new displayMetrics();        wm.getDefaultdisplay().getMetrics(metrics);        mScreenWIDth = metrics.wIDthPixels;        mScrennHeight = metrics.heightPixels;         //第一步:在构造方法里创建 GestureDetector 类        mGestureDetector = new GestureDetector(context, new myGestureListener());    }@OverrIDe    public boolean ontouchEvent(MotionEvent ev) {        //第二步:在 ontouchEvent 中拦截快速滑动手势        if (mGestureDetector.ontouchEvent(ev)){            return mGestureDetector.ontouchEvent(ev);        }        switch(ev.getAction()){            //自己处理 手指抬起事件 所以 return true            case MotionEvent.ACTION_UP:            {                //就是这里要注意,因为最开始 getScrollX() 的值是 mMenuWIDth                if (getScrollX() > mMenuWIDth/2){                    closeMenu();                }else {                    openMenu();                }                return true;            }        }        return super.ontouchEvent(ev);    }//第三步:编写 myGestureListener private class myGestureListener extends GestureDetector.SimpleOnGestureListener {        @OverrIDe        public boolean onFling(MotionEvent e1, MotionEvent e2, float veLocityX, float veLocityY) {            System.out.println("veLocityX ->" + veLocityX);            if (menuIsOpen){                //菜单打开状态                if (veLocityX < -500){                    closeMenu();                    return true;                }            }else {                //菜单关闭状态                if (veLocityX > 500){                    openMenu();                    return true;                }            }            return false;        }    }//在下面两个方法中添加了菜单是否打开标志private voID closeMenu(){        smoothScrollTo(mMenuWIDth,0);        menuIsOpen = false;    }private voID openMenu(){        smoothScrollTo(0,0);        menuIsOpen = true;    }
优化四:根据滑动给内容页添加阴影

其实要实现这个有以下两种方法:

在 xml 中静态添加 VIEw 覆盖层 

在 java 代码中动态添加 VIEw 覆盖层(复用性好,我们选择这一种)

 @OverrIDe    protected voID onFinishInflate() {        super.onFinishInflate();        //获取子代        VIEwGroup ll_child = (VIEwGroup) getChildAt(0);        mMenu = ll_child.getChildAt(0);        mContent = ll_child.getChildAt(1);        //设置菜单 内容的宽度        mMenuWIDth = mMenu.getLayoutParams().wIDth = mScreenWIDth - 400;        //第一步:先把以前的内容 从线性布局中移除        ll_child.removeVIEw(mContent);        //第二步:创建一个帧布局        FrameLayout contentFrameLayout = new FrameLayout(getContext());        //第三步:把以前的内容 加入到这个帧布局中        contentFrameLayout.addVIEw(mContent);        //第四步:创建一个阴影 层        mShadeVIEw = new VIEw(getContext());        //给阴影层设置颜色        mShadeVIEw.setBackgroundcolor(color.parsecolor("#550000"));        //第五步:将这个阴影层加入帧布局中,覆盖在内容之上        contentFrameLayout.addVIEw(mShadeVIEw);        //第六步:给帧布局设置宽度        VIEwGroup.LayoutParams params = new VIEwGroup.LayoutParams(VIEwGroup.LayoutParams.MATCH_PARENT, VIEwGroup.LayoutParams.MATCH_PARENT);        params.wIDth = mScreenWIDth;        contentFrameLayout.setLayoutParams(params);        //第七步:将这个帧布局添加进来        ll_child.addVIEw(contentFrameLayout);        //第八步:将阴影层设为透明        mShadeVIEw.setAlpha(0.0f);    }    @OverrIDe    protected voID onScrollChanged(int l, int t, int oldl, int oldt) {        super.onScrollChanged(l, t, oldl, oldt);        //计算比例因子 1 -> 0        float rate = l/(float)mMenuWIDth;        //根据比例因子设置透明度        mShadeVIEw.setAlpha(1-rate);    }

最终效果

有偿提问

如果大家觉得这篇文章帮助你了,可以支持一下。

有偿提问

总结

以上是内存溢出为你收集整理的仿QQ6.0主页面侧滑效果(第二种实现方法)全部内容,希望文章能够帮你解决仿QQ6.0主页面侧滑效果(第二种实现方法)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1012033.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-22
下一篇2022-05-22

发表评论

登录后才能评论

评论列表(0条)

    保存