QQ侧滑效果的实现与思考

看到很多APP都用到的侧滑效果,由于自己也是自学的初学者,就在网上找了学习资料学习了一下,代码基本上都来自慕课网,在此整理记录一下,方便以后查看,也希望对别人有点帮助!

1.首先写布局文件,侧滑效果其实是在一个activity里添加了2个布局文件(我个人是这么理解的),就像是一张A4纸被横向拉伸了一样。只是我们只能看到一张A4纸张的大小!
1.1侧滑菜单的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical"
         >

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="10dp"
                android:layout_toRightOf="@+id/ig_01"
                android:text="第一行"
                android:textSize="30sp" />

            <ImageView
                android:id="@+id/ig_01"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_alignParentLeft="true"
                android:layout_alignParentTop="true"
                android:layout_marginLeft="20dp"
                android:src="@drawable/img_1" />
        </RelativeLayout>
         <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="10dp"
                android:layout_toRightOf="@+id/ig_02"
                android:text="第一行"
                android:textSize="30sp" />

            <ImageView
                android:id="@+id/ig_02"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_alignParentLeft="true"
                android:layout_alignParentTop="true"
                android:layout_marginLeft="20dp"
                android:src="@drawable/img_1" />
        </RelativeLayout>


    </LinearLayout>

</RelativeLayout>

效果:这里写图片描述
1.2主布局,这里当然需要写一个继承HorizontalScrollView的自定义布局文件,
注意第一个LinearLayout的宽度是包裹内容,我自己的理解是要包含2个布局肯定不能是匹配了

RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:lly="http://schemas.android.com/apk/res/com.example.qqtest"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.SlidingMenu.SlidingMeny
        android:id="@+id/id_menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/img_frame_background"
        lly:rightPadding="100dp" >

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

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

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/qq" >

                <Button
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:onClick="toggle"
                    android:text="菜单" />
            </LinearLayout>
        </LinearLayout>
    </com.example.SlidingMenu.SlidingMeny>

</RelativeLayout>

效果图:这里写图片描述

1.3 自定义布局文件,由于也是自学,我的注释也写的很详细了

package com.example.SlidingMenu;

import com.example.qqtest.R;
import com.nineoldandroids.view.ViewHelper;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

public class SlidingMeny extends HorizontalScrollView {
    private LinearLayout mWapper; // 布局
    private ViewGroup mMenu;// 菜单布局
    private ViewGroup mContent;// 主内容
    private int mMenuWidth;// 菜单宽度
    private int mContentWidth;// 内容宽度
    private int mScreenWidth;// 屏幕宽度
    private int mPaddingRight = 50;// 菜单距离右边距离
    boolean once;// 只获取一次屏幕宽度的标示符
    boolean isopen;// 菜单是否打开标示符(默认值是false)

    /**
     * 设置子view的宽和高(第一步)
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (!once) {// 确保只调用一次

            mWapper = (LinearLayout) getChildAt(0);
            mMenu = (ViewGroup) mWapper.getChildAt(0);
            mContent = (ViewGroup) mWapper.getChildAt(1);
            // menu的宽度
            mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mPaddingRight;
            // content的宽度
            mContentWidth = mContent.getLayoutParams().width = mScreenWidth;
            once = true;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 没有使用自定义属性的时候调用(第二步)
     * 
     * @param context
     */
    public SlidingMeny(Context context) {
        this(context, null);
    }

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

    /**
     * 有自定义的属性时候调用(第三步),并且去values去自定义属性
     * 
     * @param context
     * @param attrs
     * @param defStyleAttr
     */

    public SlidingMeny(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 获取定义属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.slidingM, defStyleAttr, 0);
        // 获取自定义属性的数量
        int n = array.getIndexCount();
        // 遍历自定义属性
        for (int i = 0; i < n; i++) {
            int attr = array.getIndex(i);
            switch (attr) {
            case R.styleable.slidingM_rightPadding:
                // 如果没有写值 就使用默认值50dp,此方法能是把dp转换为像素
                mPaddingRight = array.getDimensionPixelSize(attr, (int) TypedValue
                        .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()));
                break;
            }
        }
        // 用完要释放掉
        array.recycle();
        // 获取屏幕宽度
        WindowManager wm = (WindowManager) context.getSystemService(context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        mScreenWidth = outMetrics.widthPixels;

    }

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

    /**
     * 手指动作,判断用户手指抬起的时候的装填(第五步)
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
        case MotionEvent.ACTION_UP:// 用户手指抬起时候
            int scollX = getScrollX();// 获取X轴滑动的距离
            if (scollX >= mMenuWidth / 2) {// X轴距离大于左侧菜单宽度的二分之一就滑动界面
                this.smoothScrollTo(mMenuWidth, 0);// 滑动的距离和动画
                isopen = false;// 并将菜单表示符号置为false

            } else {
                this.smoothScrollTo(0, 0);// 小于二分之一就不滑动界面,返回到原来的
                isopen = true;
            }
            return true;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 抽屉式效果(第六步)
     */
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        float scall = l * 1.0f / mMenuWidth;// 缩放比例(可以自己写出自己想要的效果)
        float rightScale = (float) (0.7 + 0.3 * scall);// 右侧缩放
        float leftScale = (float) (1.0 - 0.3 * scall);// 左侧缩放
        float leftAlpha = (float) (1 - 0.4 * scall);// 透明度
        // menu的缩放点以及缩放动画 此时要导入第三方的包,兼容3.0一下。nineoldandroids-2.4.0.jar
        ViewHelper.setPivotX(mMenu, leftScale);// 设置缩放点
        ViewHelper.setPivotY(mMenu, leftScale);
        ViewHelper.setTranslationX(mMenu, mMenuWidth * scall * 0.7f);// 设置缩放动画
        ViewHelper.setAlpha(mMenu, leftAlpha);
        // content 设置缩放的中心点在左边框的中心以及缩放的比例
        ViewHelper.setPivotX(mContent, 0);
        ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
        ViewHelper.setScaleX(mContent, rightScale);
        ViewHelper.setScaleY(mContent, rightScale);

    }

    /**
     * 打开菜单
     */
    public void openMenu() {
        if (isopen)
            return;
        this.smoothScrollTo(0, 0);
        isopen = true;
    }

    /**
     * 关闭菜单
     */
    public void closeMenu() {
        if (!isopen)
            return;
        this.smoothScrollTo(mMenuWidth, 0);
        isopen = false;
    }

    /**
     * 切换菜单
     */
    public void toggle() {
        if (isopen) {
            closeMenu();
        } else {
            openMenu();
        }
    }

}

1.4 最后在MainActivity里调用,这里只需要注意此处要在主activity里面的自定义布局添加id

package com.example.qqtest;

import com.example.SlidingMenu.SlidingMeny;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;

public class MainActivity extends Activity {

    private SlidingMeny meny;// 获取自定义布局的ID

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        meny = (SlidingMeny) findViewById(R.id.id_menu);
    }

    public void toggle(View view) {
        meny.toggle();// 调用开关
    }
}

这个包百度一下就可以找到!
nineoldandroids-2.4.0.jar

1.4自定义属性,在values里新建

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="slidingM">
        <attr name="rightPadding" format="dimension"></attr>
    </declare-styleable>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值