QQ主界面的滑动效果的实现(xml中定义布局属性)

来源:互联网 发布:淘宝店加权重有哪些 编辑:程序博客网 时间:2024/05/25 21:33

需要注意的时本例中导入了com.nineoldandroids.view.ViewHelper的包,还用到了常用的ScreenUtils 辅助类来获取屏幕的信息。jar包可以在网盘中寻找。

另外,关于动画可参考http://code1.okbase.net/codefile/ViewHelper.java_2014032025926_38.htm

本文参照:http://blog.csdn.net/lmj623565791/article/details/39257409
更高级用法:http://blog.csdn.net/lmj623565791/article/details/41531475
神级用法:http://blog.csdn.net/lmj623565791/article/details/39670935

所以在以后的实践中要注意jar的使用,以及常用辅助类的总结

主程序

package com.test.mysideslip;import android.support.v7.app.ActionBarActivity;import com.test.sideslip.SlidingMenu;import android.app.Activity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.Window;import android.widget.LinearLayout;public class MainActivity extends Activity {     private SlidingMenu mMenu;         private LinearLayout mLinearLayout;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);         requestWindowFeature(Window.FEATURE_NO_TITLE);          setContentView(R.layout.activity_main);        mMenu = (SlidingMenu) findViewById(R.id.id_menu);    }      public void toggle_Menu(View view)          {              mMenu.toggle();          }        public void linear_toggle_Menu(View view){          //实现一点击主页面时,就进入主页面          mMenu.toggle();      }}

滑动效果实现的主要程序

package com.test.sideslip;import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.util.TypedValue;import android.view.MotionEvent;import android.view.ViewGroup;import android.widget.HorizontalScrollView;import android.widget.LinearLayout;import com.nineoldandroids.view.ViewHelper;import com.test.mysideslip.R;public class SlidingMenu extends HorizontalScrollView{    /**     * 屏幕宽度     */    private int mScreenWidth;    /**     * dp     */    private int mMenuRightPadding;    /**     * 开始隐藏菜单的宽度     */    private int mMenuWidth;    private int mHalfMenuWidth;    private boolean isOpen;    private boolean once;    private ViewGroup mMenu;    private ViewGroup mContent;    public SlidingMenu(Context context, AttributeSet attrs)    {        this(context, attrs, 0);    }    public SlidingMenu(Context context, AttributeSet attrs, int defStyle)    {        super(context, attrs, defStyle);        mScreenWidth = ScreenUtils.getScreenWidth(context);        //类型的数组,得到所有theme        //Sliding属性是定义在xml文件中的        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,                R.styleable.SlidingMenu, defStyle, 0);        int n = a.getIndexCount();        for (int i = 0; i < n; i++)        {            int attr = a.getIndex(i);            switch (attr)            {            case R.styleable.SlidingMenu_rightPadding:                // 默认50,后面传入的为默认值                mMenuRightPadding = a.getDimensionPixelSize(attr,                        (int) TypedValue.applyDimension(                                TypedValue.COMPLEX_UNIT_DIP, 50f,                                getResources().getDisplayMetrics()));                break;            }        }        a.recycle();    }    public SlidingMenu(Context context)    {        this(context, null, 0);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)    {        /**         * 显示的设置一个宽度         */        if (!once)        {            LinearLayout wrapper = (LinearLayout) getChildAt(0);            mMenu = (ViewGroup) wrapper.getChildAt(0);            mContent = (ViewGroup) wrapper.getChildAt(1);            //需要注意的mMenuWidth是屏幕的总宽度减去已经隐藏起来的右边内容的宽度            //所以mMenuWidth会越来越小。            mMenuWidth = mScreenWidth - mMenuRightPadding;            mHalfMenuWidth = mMenuWidth / 2;            mMenu.getLayoutParams().width = mMenuWidth;            //在屏幕上显示的部分            mContent.getLayoutParams().width = mScreenWidth;        }        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);        if (changed)        {            // 将菜单隐藏            this.scrollTo(mMenuWidth, 0);            once = true;        }    }    @Override    public boolean onTouchEvent(MotionEvent ev)    {        int action = ev.getAction();        switch (action)        {        // Up时,进行判断,如果显示区域大于菜单宽度一半则完全显示,否则隐藏        case MotionEvent.ACTION_UP:            int scrollX = getScrollX();            if (scrollX > mHalfMenuWidth)            {                //菜单就是最开始的隐藏部分                this.smoothScrollTo(mMenuWidth, 0);                isOpen = false;            } else            {                this.smoothScrollTo(0, 0);                isOpen = true;            }            return true;        }        return super.onTouchEvent(ev);    }    //下面的三个方法完全是为了左上角的按钮切换。    /**     * 打开菜单     */    public void openMenu()    {        if (isOpen)            return;        this.smoothScrollTo(0, 0);        isOpen = true;    }    /**     * 关闭菜单     */    public void closeMenu()    {        if (isOpen)        {            this.smoothScrollTo(mMenuWidth, 0);            isOpen = false;        }    }    /**     * 切换菜单状态     */    public void toggle()    {        if (isOpen)        {            closeMenu();        } else        {            openMenu();        }    }    @Override    protected void onScrollChanged(int l, int t, int oldl, int oldt)    {        super.onScrollChanged(l, t, oldl, oldt);          //得到左边隐藏宽度的单位宽度        float scale = l * 1.0f / mMenuWidth;          //左边的缩小比例        float leftScale = 1 - 0.3f * scale;          //右边的缩小比例        float rightScale = 0.8f + scale * 0.2f;          //放大缩小布局文件        ViewHelper.setScaleX(mMenu, leftScale);          ViewHelper.setScaleY(mMenu, leftScale);          ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));          ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.6f);          //设置缩放的中心线,就是scale时沿哪条中心线进行缩放。        ViewHelper.setPivotX(mContent, 0);          ViewHelper.setPivotY(mContent, mContent.getHeight()/2 );          //之所以用这个值的原因已经在onMeasure中解释        ViewHelper.setScaleX(mContent, rightScale);          ViewHelper.setScaleY(mContent, rightScale);      }}

屏幕测量辅助类

package com.test.sideslip;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Rect;import android.util.DisplayMetrics;import android.view.View;import android.view.WindowManager;public class ScreenUtils {    private ScreenUtils() {        /* cannot be instantiated */        throw new UnsupportedOperationException("cannot be instantiated");    }    /**     * 获得屏幕高度     *      * @param context     * @return     */    public static int getScreenWidth(Context context) {        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        DisplayMetrics outMetrics = new DisplayMetrics();        wm.getDefaultDisplay().getMetrics(outMetrics);        return outMetrics.widthPixels;    }    /**     * 获得屏幕宽度     *      * @param context     * @return     */    public static int getScreenHeight(Context context) {        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        DisplayMetrics outMetrics = new DisplayMetrics();        wm.getDefaultDisplay().getMetrics(outMetrics);        return outMetrics.heightPixels;    }    /**     * 获得状态栏的高度     *      * @param context     * @return     */    public static int getStatusHeight(Context context) {        int statusHeight = -1;        try {            Class<?> clazz = Class.forName("com.android.internal.R$dimen");            Object object = clazz.newInstance();            int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());            statusHeight = context.getResources().getDimensionPixelSize(height);        } catch (Exception e) {            e.printStackTrace();        }        return statusHeight;    }    /**     * 获取当前屏幕截图,包含状态栏     *      * @param activity     * @return     */    public static Bitmap snapShotWithStatusBar(Activity activity) {        View view = activity.getWindow().getDecorView();        view.setDrawingCacheEnabled(true);        view.buildDrawingCache();        Bitmap bmp = view.getDrawingCache();        int width = getScreenWidth(activity);        int height = getScreenHeight(activity);        Bitmap bp = null;        bp = Bitmap.createBitmap(bmp, 0, 0, width, height);        view.destroyDrawingCache();        return bp;    }    /**     * 获取当前屏幕截图,不包含状态栏     *      * @param activity     * @return     */    public static Bitmap snapShotWithoutStatusBar(Activity activity) {        View view = activity.getWindow().getDecorView();        view.setDrawingCacheEnabled(true);        view.buildDrawingCache();        Bitmap bmp = view.getDrawingCache();        Rect frame = new Rect();        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);        int statusBarHeight = frame.top;        int width = getScreenWidth(activity);        int height = getScreenHeight(activity);        Bitmap bp = null;        bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight);        view.destroyDrawingCache();        return bp;    }}

主布局文件

<com.test.sideslip.SlidingMenu xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:zhy="http://schemas.android.com/apk/res/com.test.mysideslip"    android:layout_width="wrap_content"    android:layout_height="fill_parent"    android:scrollbars="none"    android:id="@+id/id_menu"     zhy:rightPadding="100dp"     android:background="@drawable/c"     >    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="fill_parent"        android:orientation="horizontal" >        <include layout="@layout/layout_menu" />        <LinearLayout            android:id="@+id/main_pager_layout"            android:layout_width="fill_parent"            android:layout_height="fill_parent"            android:background="@drawable/c"             android:onClick="linear_toggle_Menu" >            <Button                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:onClick="toggle_Menu"                android:text="切换菜单" />        </LinearLayout>    </LinearLayout></com.test.sideslip.SlidingMenu>

layout_menu.xml布局文件

<?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_centerVertical="true"        android:orientation="vertical" >        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="wrap_content" >            <ImageView                android:id="@+id/one"                android:layout_width="50dp"                android:layout_height="50dp"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_marginTop="20dp"                android:src="@drawable/c" />            <TextView                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_toRightOf="@id/one"                android:text="第1个Item"                android:textColor="#f0f0f0"                android:textSize="20sp" />        </RelativeLayout>        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="wrap_content" >            <ImageView                android:id="@+id/two"                android:layout_width="50dp"                android:layout_height="50dp"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_marginTop="20dp"                android:src="@drawable/b" />            <TextView                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_toRightOf="@id/two"                android:text="第2个Item"                android:textColor="#f0f0f0"                android:textSize="20sp" />        </RelativeLayout>        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="wrap_content" >            <ImageView                android:id="@+id/three"                android:layout_width="50dp"                android:layout_height="50dp"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_marginTop="20dp"                android:src="@drawable/b" />            <TextView                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_toRightOf="@id/three"                android:text="第3个Item"                android:textColor="#f0f0f0"                android:textSize="20sp" />        </RelativeLayout>        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="wrap_content" >            <ImageView                android:id="@+id/four"                android:layout_width="50dp"                android:layout_height="50dp"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_marginTop="20dp"                android:src="@drawable/b" />            <TextView                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_toRightOf="@id/four"                android:text="第一个Item"                android:textColor="#f0f0f0"                android:textSize="20sp" />        </RelativeLayout>        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="wrap_content" >            <ImageView                android:id="@+id/five"                android:layout_width="50dp"                android:layout_height="50dp"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_marginTop="20dp"                android:src="@drawable/b" />            <TextView                android:layout_width="fill_parent"                android:layout_height="wrap_content"                android:layout_centerVertical="true"                android:layout_marginLeft="20dp"                android:layout_toRightOf="@id/five"                android:text="第5个Item"                android:textColor="#f0f0f0"                android:textSize="20sp" />        </RelativeLayout>    </LinearLayout></RelativeLayout>

效果图

这里写图片描述

当这样写时可以实现另一种效果

@Override      protected void onScrollChanged(int l, int t, int oldl, int oldt)      {          super.onScrollChanged(l, t, oldl, oldt);          float scale = l * 1.0f / mMenuWidth;  //      float leftScale = 1 - 0.3f * scale;  //      float rightScale = 0.8f + scale * 0.2f;  //        //      ViewHelper.setScaleX(mMenu, leftScale);  //      ViewHelper.setScaleY(mMenu, leftScale);  //      ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));          ViewHelper.setTranslationX(mMenu, mMenuWidth * scale );  //      ViewHelper.setPivotX(mContent, 0);  //      ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);  //      ViewHelper.setScaleX(mContent, rightScale);  //      ViewHelper.setScaleY(mContent, rightScale);      }  

3、动画比例的计算

我们在onScrollChanged里面,拿到 l 也就是个getScrollX,即菜单已经显示的宽度值;

[html] view plaincopy在CODE上查看代码片派生到我的代码片
float scale = l * 1.0f / mMenuWidth;

与菜单的宽度做除法运算,在菜单隐藏到显示整个过程,会得到1.0~0.0这么个变化的区间;
有了这个区间,就可以根据这个区间设置动画了;

1、首先是内容区域的缩放比例计算:

我们准备让在菜单出现的过程中,让内容区域从1.0~0.8进行变化~~

那么怎么把1.0~0.0转化为1.0~0.8呢,其实很简单了:

float rightScale = 0.8f + scale * 0.2f; (scale 从1到0 ),是不是哦了~

接下来还有3个动画:

2、菜单的缩放比例计算

仔细观察了下QQ,菜单大概缩放变化是0.7~1.0

float leftScale = 1 - 0.3f * scale;

3、菜单的透明度比例:

我们设置为0.6~1.0;即:0.6f + 0.4f * (1 - scale)

4、菜单的x方向偏移量:

看一下QQ,并非完全从被内容区域覆盖,还是有一点拖出的感觉,所以我们的偏移量这么设置:

tranlateX = mMenuWidth * scale * 0.6f ;刚开始还是让它隐藏一点点~~~

0 0
原创粉丝点击