继承ViewGoup,重写onInterceptTouchEvent截拦触摸事件并按条件分发给子View。
package com.example.viewdemo;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
public class SliderView extends ViewGroup {
/**
* 速度边界
*/
private static final int VELOCITY_X_SPEED = 800;
/**
* 最后一次触摸的x位置
*/
private float x;
private Scroller scroller;
/**
* 触摸事件是否已分发给子view
*/
private boolean dispatched;
private boolean slided;
private int startScrollLeftOffset;
private VelocityTracker mVelocityTracker;
public SliderView(Context context, AttributeSet attrs) {
super(context, attrs);
scroller = new Scroller(context);
}
@Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
int childCount = getChildCount();
for (int i = 0; i < childCount; ++i) {
View view = getChildAt(i);
if (view.getVisibility() != View.GONE) {
view.layout(0, 0, view.getMeasuredWidth(),
view.getMeasuredHeight());
}
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
x = event.getX();
//分发事件
if (isSlided()) {
dispatched = dispatchTouchEventToView(getChildAt(0), event);
} else {
dispatched = dispatchTouchEventToView(getChildAt(1), event);
}
} else if (action == MotionEvent.ACTION_MOVE) {
if (dispatched) {//分发事件
if (isSlided()) {
dispatchTouchEventToView(getChildAt(0), event);
} else {
dispatchTouchEventToView(getChildAt(1), event);
}
} else {//重置第一个子view位置
float dx = event.getX() - x;
View view = getChildAt(1);
int left = (int) (view.getLeft() + dx);
if (left >= 0) {
view.layout(left, view.getTop(), view.getWidth() + left,
view.getTop() + view.getHeight());
}
}
x = event.getX();
} else if (action == MotionEvent.ACTION_CANCEL
|| action == MotionEvent.ACTION_UP) {
if (dispatched) {//分发事件
if (isSlided()) {
dispatchTouchEventToView(getChildAt(0), event);
} else {
dispatchTouchEventToView(getChildAt(1), event);
}
} else {
//判断速度
mVelocityTracker.computeCurrentVelocity(1000);
int velocityX = (int) mVelocityTracker.getXVelocity();
if (velocityX > VELOCITY_X_SPEED) {
setSlided(true);
} else if (velocityX < -VELOCITY_X_SPEED) {
setSlided(false);
} else {
View view = getChildAt(1);
if (view.getLeft() >= view.getWidth() / 2) {
setSlided(true);
} else {
setSlided(false);
}
}
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
}
}
}
return true;
}
public boolean isSlided() {
return slided;
}
/**
* 设置是否滑动显示菜单状态,并动画滑动效果
* @param slided
*/
public void setSlided(boolean slided) {
View view = getChildAt(1);
startScrollLeftOffset = view.getLeft();
if (slided) {
scroller.startScroll(0, getTop(), view.getWidth() * 3 / 4
- startScrollLeftOffset, 0);
} else {
scroller.startScroll(0, getTop(), -startScrollLeftOffset, 0);
}
this.slided = slided;
postInvalidate();
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
View view = getChildAt(1);
int left = startScrollLeftOffset + scroller.getCurrX();
view.layout(left, view.getTop(), left + view.getWidth(),
view.getHeight());
postInvalidate();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
for (int i = 0; i < getChildCount(); ++i) {
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
}
public boolean dispatchTouchEventToView(View view, MotionEvent ev) {
try {
return view.dispatchTouchEvent(ev);
} catch (Exception e) {
// 部分机型会抛异常
e.printStackTrace();
}
return false;
}
}
------------------------------------------------------例子
package com.example.viewdemo;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener,
OnItemClickListener {
SliderView sliderView;
ListView listView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sliderView = (SliderView) findViewById(R.id.slider_view);
Button button1 = (Button) findViewById(R.id.button1);
Button button2 = (Button) findViewById(R.id.button2);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
listView = (ListView) findViewById(R.id.listView);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, new String[] { "GOOD",
"HAHA", "What is that?", "FUUUUCK" });
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
sliderView.setSlided(!sliderView.isSlided());
return true;
}
@Override
public void onClick(View v) {
Toast.makeText(this, ((Button) v).getText().toString(),
Toast.LENGTH_LONG).show();
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
String string = (String) arg0.getItemAtPosition(arg2);
Toast.makeText(this, string, Toast.LENGTH_LONG).show();
}
}
----------------------------------------------布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.example.viewdemo.SliderView
android:id="@+id/slider_view"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="3"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="hello" />
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
</ListView>
</LinearLayout>
<LinearLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" >
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:gravity="center" >
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="world" />
</LinearLayout>
</com.example.viewdemo.SliderView>
</LinearLayout>