仿QQ5.0侧滑先行版

QQ5.0侧滑效果实现方案有很多方式,今天先来介绍一种简单的方式

先上效果图:
模仿QQ5.0侧滑效果

①我们先来分析一下,如果想要滑动效果,哪些控件具有滑动效果呢?于是我们想到了ScrollView, HorizontalScrollView, ListView… 通过对比,我们可以找出HorizontalScrollView最符合我们的效果。使用HorizontalScrollView,在适当的时候隐藏部分HorizontalScrollView的内容即可。因此我的自定义View继承HorizontalScrollView就可以了。

/** SlidingMenu就是我们自定义的View控件 */
public class SlidingMenu extends HorizontalScrollView {

    private ViewGroup mWapper;// SlidingMenu中的LinearLayout
    private ViewGroup mMenu;// 菜单
    private ViewGroup mContent;// 主页面内容

    private boolean isFirstMeasure = true;// 是否首次测量
    private int mMenuRightPadding = 150;// 菜单右边预留宽度

    private int mScreentWidth;// 屏幕宽度
    private int mMenuWidth;// 菜单宽度
    private boolean isOpen = false;// 是否打开菜单

    /** 需要重写构造方法 */
    public SlidingMenu(Context context) {
        this(context, null);
    }

    public SlidingMenu(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        // 获取自定义的属性
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu, defStyleAttr, 0);
        int count = a.getIndexCount();
        for (int i = 0; i < count; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.SlidingMenu_rightPadding:
                    mMenuRightPadding = a.getDimensionPixelSize(attr, dp2px(context, mMenuRightPadding)); // 获取到自定义属性rightPadding的值,即菜单预留宽度
                    break;
            }
        }
        a.recycle();// 需要及时销毁

        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);// 得到窗口管理器
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        mScreentWidth = outMetrics.widthPixels;// 获取屏幕的宽度
}

/** dp转px */
public int dp2px(Context context, int i) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, i, context.getResources().getDisplayMetrics());
    }

使用自定义控件,自定义属性。在values/attr.xml中定义
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <attr name="rightPadding" format="dimension"/>

        <declare-styleable name="SlidingMenu">
            <attr name="rightPadding"/>
        </declare-styleable>
    </resources>

②接着定义下我们主页面的布局文件,使用我们自定义的SlidingMenu控件。布局文件中,我们自定义SlidingMenu中用了LinearLayout, LinearLayout中包含了一个左边布局和主页面的布局。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:lingchen="http://schemas.android.com/apk/res-auto"//如果需要给自定义控件添加属性,需要在这里定义下命名空间
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.yitong.myslidingmenu.MainActivity">

    <com.yitong.myslidingmenu.view.SlidingMenu
        android:id="@+id/main_menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@mipmap/bg"
        android:fadingEdge="none"
        android:overScrollMode="never"
        lingchen:rightPadding="60dp"//向自定控件传递值
        >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal">

            <include layout="@layout/left_menu"/>

            <LinearLayout
                android:id="@+id/main_content"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@mipmap/qq"
                android:orientation="horizontal">

                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:onClick="click"
                    android:text="切换菜单"/>

            </LinearLayout>
        </LinearLayout>

    </com.yitong.myslidingmenu.view.SlidingMenu>
</RelativeLayout>

③接着,回到我们的SlidingMenu中,重写onMeasure(测量控件),onLayout(重新布局)

   @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (isFirstMeasure) {// 防止重复测量
            mWapper = (ViewGroup) getChildAt(0);//获取第一个孩子,即主页面布局中SlidingMenu包含的LinearLayout
            mMenu = (ViewGroup) mWapper.getChildAt(0);// 左边布局(菜单布局)
            mContent = (ViewGroup) mWapper.getChildAt(1);// 主布局
            mMenuWidth = mScreentWidth - mMenuRightPadding - mMenuRightPadding;// 菜单布局的宽度 = 屏幕的宽度 - 右边预留的宽度
            mMenu.getLayoutParams().width = mMenuWidth;// 设置菜单的宽度
            isFirstMeasure = false;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);
     // 通过设置偏移量,将menu隐藏
     if (changed) {
         this.scrollTo(mMenuWidth, 0);
     }
 }

③此时,我们的自定义SlingMenu,大致已经设计好了,是不是能简单呢。然后我们添加一些效果,当菜单滑出一半多时,让它自定滑出,否则让它关闭。

 @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:// 手指抬起时
                int scrollX = getScrollX();// 获取左边隐藏的宽度
                if (scrollX > mMenuWidth / 2) { // 关闭menu
                    this.smoothScrollTo(mMenuWidth, 0);
                    isOpen = false;
                } else {
                    this.smoothScrollTo(0, 0);
                    isOpen = true;
                }
                return true;
        }
        return super.onTouchEvent(ev);
    }

④当菜单打开过程中,添加动画效果,重写onScrollChanged方法即可

@Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
     super.onScrollChanged(l, t, oldl, oldt);
     float scale = l * 1.0f / mMenuWidth;// 1-0
     /**
      * 分析:
      *
      * 内容区域:
      *          缩放1.0->0.6 => 0.6+0.4*scale
      *
      * 菜单区域:
      *          位移
      *          缩放0.6->1.0 => 0.6+0.4*(1-scale)
      *          透明度0.6->1.0 => 0.3+0.7*(1-scale)
      */
     float rightScale = (float) (0.6 + 0.4 * scale);
     float leftScale = (float) (0.6 + 0.4 * (1 - scale));
     float leftAphla = (float) (0.2 + 0.7 * (1 - scale));

     // 设置内容的缩放中心点
     ViewHelper.setPivotX(mContent, 0);
     ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
     // 设置内容缩放
     ViewHelper.setScaleX(mContent, rightScale);
     ViewHelper.setScaleY(mContent, rightScale);

     // 设置菜单的位移
     ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.6f);
     ViewHelper.setScaleX(mMenu, leftScale);
     ViewHelper.setScaleY(mMenu, leftScale);
     ViewHelper.setAlpha(mMenu, leftAphla);
 }

⑤我们这个控件提供一个方法,这个方法就像一个开关按钮,可以控制打开/关闭菜单

/**
 * 切换菜单
  */
 public void toggle() {
     if (isOpen) {
         closeMenu();
     } else {
         openMenu();
     }
 }
/**
 * 打开菜单
 */
private void openMenu() {
    if (!isOpen) {
        this.smoothScrollTo(0, 0);
        isOpen = true;
    }
}

/**
 * 关闭菜单
 */
private void closeMenu() {
    if (isOpen) {
        this.smoothScrollTo(mMenuWidth, 0);
        isOpen = false;
    }
}

最后完善我们的MainActivity

public class MainActivity extends Activity {

    private LinearLayout mMainContent;
    private int mScreenWidth;// 屏幕的宽度
    private int mScreenHeight;// 屏幕的高度

    private SlidingMenu slidingMenu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        getScreenSize();
        intiView();
    }

    private void intiView() {
        mMainContent = (LinearLayout)findViewById(R.id.main_content);
        ViewGroup.LayoutParams params = mMainContent.getLayoutParams();
        // 设置主页面的宽高,防止不同手机屏幕大小不一
        params.width = mScreenWidth;
        params.height = mScreenHeight;
        slidingMenu = (SlidingMenu) findViewById(R.id.main_menu);
    }

    public void click(View view) {
        slidingMenu.toggle();
    }

    public void getScreenSize() {
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        mScreenWidth = outMetrics.widthPixels;
        mScreenHeight = outMetrics.heightPixels;
    }
}

===============至此本文档完==================
如果哪里不清楚,可以留言,博主会及时答复。源码下载,博主使用的是as开发的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值