您的位置:首页 > 其它

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

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

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

本文参照:/article/1336229.html

更高级用法:/article/1580285.html

神级用法:/article/1336224.html

所以在以后的实践中要注意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 ;刚开始还是让它隐藏一点点~~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: