他的介绍实现了qq侧滑功能,这里我简单的做一下介绍并且巩固一下自己的知识。只有自己去敲了才能发现问题。顺便
说一下苦逼的过年终于过去了,好久没写博客了。
首先说下思路,这里我主要是通过自定义HorizontalScrollView来实现一个侧滑效果。一般自定义view的话都是在
onMeasure()、onLayout()、ondraw()、onTouchEvent()还有事件分发机制方法里面做文章。这里我们主要
是通过onMeasure()方法里面测量我们添加滑动view的大小,在onLayout()方法里面设置menu view的位置。最后
在touch事件里面处理up时滑动view的位置,可能你会问为什么不在move事件里面处理呢?嘿嘿,这就是我们使
用HorizontalScrollView的优势了,move事件它已经给我们处理好了。最后实现侧滑的重点就是滑动的逻辑问题了,还
有就是实现抽屉式侧滑的属性动画。具体我们就看我一一介绍:
1.我们先来看下布局文件
首先是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"
android:orientation="vertical"
android:background="#0000"
>
<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" >
<ImageView
android:id="@+id/id_img1"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@drawable/img_1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@id/id_img1"
android:text="第一个Item"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/id_img2"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@drawable/img_2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@id/id_img2"
android:text="第二个Item"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/id_img3"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@drawable/img_3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@id/id_img3"
android:text="第三个Item"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/id_img4"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@drawable/img_4" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@id/id_img4"
android:text="第四个Item"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/id_img5"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@drawable/img_5" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@id/id_img5"
android:text="第五个Item"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/id_img6"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@drawable/img_1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@id/id_img6"
android:text="第一个Item"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
接下来就是主布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.chulu.newqqmodel.QQHorizontalScrollView
android:id="@+id/id_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/img_frame_background" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<include layout="@layout/menu" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/qq" >
<Button
android:onClick="toggleMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换菜单"
/>
</LinearLayout>
</LinearLayout>
</com.example.chulu.newqqmodel.QQHorizontalScrollView>
</RelativeLayout>
这里的布局还是很好理解的,唯一的亮点我认为就是<include>,关于ui效率可以看下api的file:///D:/adt-bundle-windows-x86_64-20131030/sdk/docs/guide/topics/resources/layout-resource.html 介绍
2.下面我们就来介绍一下自定义HorizontalScrollView
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import com.nineoldandroids.view.ViewHelper;
/**
* Created by chulu on 2015/2/28.
*/
public class QQHorizontalScrollView extends HorizontalScrollView {
/**
* 横向滚动条里面会有一个linearLayout
*/
private LinearLayout mLinearMatch;
/**
* 屏幕宽度
*/
private int mWindowWidth;
private float mMenuViewLeftPadding;
private ViewGroup mMenuView;
private ViewGroup mContentView;
/**
* menu的宽度
*/
private int mMenuWidth;
/**
* 防止测量多次长度
*/
private boolean mFirst;
/**
* 判断是否处于menu状态
*/
private boolean mIsOpen=false;
public QQHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
/**
* 得到界面宽度
*/
WindowManager manager= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);
mWindowWidth = metrics.widthPixels;
/**
* 将dp转化为px像素
*/
mMenuViewLeftPadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, context.getResources().getDisplayMetrics());
}
/**
*测量子view的长宽与父view的长宽
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 具体ViewGroup里面子View顺序我们添加的时候就知道了
*/
if(!mFirst){
mLinearMatch = (LinearLayout) getChildAt(0);
mMenuView = (ViewGroup) mLinearMatch.getChildAt(0);
mMenuWidth=mMenuView.getLayoutParams().width = (int) (mWindowWidth - mMenuViewLeftPadding);
mContentView = (ViewGroup) mLinearMatch.getChildAt(1);
mContentView.getLayoutParams().width = mWindowWidth;
mFirst = true;
}
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){
scrollTo(mMenuWidth,0);
}
}
/**
* 因为是scrollerView所以这里我们只要判断up状态就行了
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
if(getScrollX()<mMenuWidth/2){
smoothScrollTo(0,0);//平滑移动
mIsOpen = true;
}else {
smoothScrollTo( mMenuWidth,0);
mIsOpen = false;
}
return true;
}
return super.onTouchEvent(ev);
}
/**
* button touch的时候调用这个方法,点击的时候让menu view移动
*/
public void openMenu(){
if(mIsOpen){
smoothScrollTo(mMenuWidth,0);
mIsOpen = false;
}else {
smoothScrollTo(0,0);
mIsOpen = true;
}
}
/**
* 实现抽屉动画
*/
@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
float rightScale = 0.7f + 0.3f * scale;
float leftScale = 1.0f - scale * 0.3f;
float leftAlpha = 0.6f + 0.4f * (1 - scale);
/**
* 这里主要是考虑兼容问题(属性动画3.0引入),顾这里我直接调用架包实现content view的缩放动画、menu view的透明度渐变动画、menu view的缩放动画
* 如果不考虑向下兼容问题,我们可以使用Objectanimator对象来实现动画
*/
// 调用属性动画,设置TranslationX
ViewHelper.setTranslationX(mMenuView, mMenuWidth * scale * 0.8f);
ViewHelper.setScaleX(mMenuView, leftScale);
ViewHelper.setScaleY(mMenuView, leftScale);
ViewHelper.setAlpha(mMenuView, leftAlpha);
// 设置content的缩放的中心点
ViewHelper.setPivotX(mContentView, 0);
ViewHelper.setPivotY(mContentView, mContentView.getHeight() / 2);
ViewHelper.setScaleX(mContentView, rightScale);
ViewHelper.setScaleY(mContentView, rightScale);
}
}
下面说下动画的逻辑:
2.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.2、菜单的缩放比例计算
仔细观察了下QQ,菜单大概缩放变化是0.7~1.0
float leftScale = 1 - 0.3f * scale;
2.3、菜单的透明度比例:
我们设置为0.6~1.0;即:0.6f + 0.4f * (1 - scale)
2.4、菜单的x方向偏移量:
看一下QQ,并非完全从被内容区域覆盖,还是有一点拖出的感觉,所以我们的偏移量这么设置:
tranlateX = mMenuWidth * scale * 0.6f ;
3.最后就是我们的收尾ManActivity了,里面也很简单就是添加了一个点击事件
<span style="font-size:18px;">import android.app.Activity;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageButton;
public class MainActivity extends Activity {
private QQHorizontalScrollView mScrollView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mScrollView = (QQHorizontalScrollView) findViewById(R.id.id_menu);
}
public void toggleMenu(View view ){
mScrollView.openMenu();
}
}
</span>
最后我发一下效果图,动态图还没baidu~还不会~先发下截图吧ovo