去年就一直纠结这个问题,也一直没想出解决办法,今年转行不做
安卓了,今天把程序翻出来看看,无意间想到解决办法就试了一下,发现还不错,立马上来分享。
简单的listview使用我就不多说了,先说模块的左右滑动,废话不多说,先上代码。
package com.huicui.music.custom;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
import com.huicui.music.custominterface.OnViewChangeListener;
import com.huicui.music.util.BaseTools;
/**
*@author zero (975804495@qq.com)
*@date 2012-10-19
*/
public class MyScrollLayout extends ViewGroup{
private static final String TAG = "ScrollLayout";
private VelocityTracker mVelocityTracker;
private static final int SNAP_VELOCITY = 600;
private Scroller mScroller;
private int mCurScreen;
private int mDefaultScreen = 0;
private float mLastMotionX;
// private int mTouchSlop;
// private static final int TOUCH_STATE_REST = 0;
// private static final int TOUCH_STATE_SCROLLING = 1;
// private int mTouchState = TOUCH_STATE_REST;
private OnViewChangeListener mOnViewChangeListener;
public MyScrollLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
init(context);
}
public MyScrollLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init(context);
}
public MyScrollLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init(context);
}
private void init(Context context)
{
mCurScreen = mDefaultScreen;
// mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
mScroller = new Scroller(context);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//if (changed) {
int childLeft = 0;
final int childCount = getChildCount();
for (int i=0; i<childCount; i++) {
final View childView = getChildAt(i);
if (childView.getVisibility() != View.GONE) {
final int childWidth = childView.getMeasuredWidth();
childView.layout(childLeft, 0,childLeft+childWidth, childView.getMeasuredHeight());//left top right bottom
childLeft += childWidth;
}
}
// }
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
scrollTo(mCurScreen * width, 0);
}
/**Calculation the point*/
public void snapToDestination() {
final int screenWidth = getWidth();
final int destScreen = (getScrollX()+ screenWidth/2)/screenWidth;
snapToScreen(destScreen);
}
public void snapToScreen(int whichScreen) {
// get the valid layout page
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount()-1));//key the right point
//Log.e("MyScrollLayout","print the getScroll" + getScrollX());
if (getScrollX() != (whichScreen*getWidth())) {
BaseTools.Log(TAG, "getScrollX:" + getScrollX(), 3);
final int delta = whichScreen*getWidth()-getScrollX();
mScroller.startScroll(getScrollX(), 0,delta, 0, Math.abs(delta)*2);//the start point ,the distance ,the duration time
mCurScreen = whichScreen;
invalidate();//repaint
// Redraw the layout
if (mOnViewChangeListener != null)
{
mOnViewChangeListener.OnViewChange(mCurScreen);
}
}
}
@Override
public void computeScroll() {
// TODO Auto-generated method stub
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
BaseTools.Log(TAG, "OnTouch--------", 1);
final int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.i("", "onTouchEvent ACTION_DOWN");
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(event);
}
if (!mScroller.isFinished()){
mScroller.abortAnimation();
}
mLastMotionX = x;
break;
case MotionEvent.ACTION_MOVE:
Log.i("", "onTouchEvent ACTION_MOVE");
int deltaX = (int)(mLastMotionX - x);
if (IsCanMove(deltaX))
{
if (mVelocityTracker != null)
{
mVelocityTracker.addMovement(event);
}
mLastMotionX = x;
scrollBy(deltaX, 0);
}
break;
case MotionEvent.ACTION_UP:
int velocityX = 0;
if (mVelocityTracker != null)
{
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
velocityX = (int) mVelocityTracker.getXVelocity();
}
if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {
// Fling enough to move left
//Log.e(TAG, "snap left:" + velocityX);
snapToScreen(mCurScreen - 1);
} else if (velocityX < -SNAP_VELOCITY
&& mCurScreen < getChildCount() - 1) {
// Fling enough to move right
//Log.e(TAG, "snap right:" + velocityX);
snapToScreen(mCurScreen + 1);
} else {
//Log.e(TAG, "do the action according to the getScrollX()");
snapToDestination();
}
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
// mTouchState = TOUCH_STATE_REST;
break;
}
return true;
}
/**judge Boundary*/
public boolean IsCanMove(int deltaX)
{
if(getScrollX() <= 0 && deltaX < 0 )
{
return false;
}
if(getScrollX() >= (getChildCount() - 1) * getWidth() && deltaX > 0)
{
return false;
}
return true;
}
/**set listener*/
public void SetOnViewChangeListener(OnViewChangeListener listener)
{
mOnViewChangeListener = listener;
}
}
这个类说白了就是利用Scroller实现滚动,基本没什么技术含量,注意snapToScreen()方法,这个是用来翻页调用的,比如触发了翻到第二页事件,只要穿进参数1就好了,Activity调用时直接在xml里面定义,例如:
<com.huicui.music.custom.MyScrollLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/topiclayout"
android:layout_above="@+id/control"
android:id="@+id/mainscroll"
>
<RelativeLayout android:background="@drawable/w01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.huicui.music.custom.MyListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/mainlistview"
>
</com.huicui.music.custom.MyListView>
</RelativeLayout>
<RelativeLayout android:background="@drawable/w02"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
</RelativeLayout>
</com.huicui.music.custom.MyScrollLayout>
下面是重头戏,(我的listview也是自定义控件),要实现上下和左右滑动无非就是判断什么时候把焦点给listview和父控件,但是这个父控件焦点获取我一直没有搞好,不知道该怎么做,什么方法都试过了,listview不是死死控制着焦点就算滑动混乱,今天突然灵机一动,也许我可以让listview的touch事件return true,然后人为控制滑动动画就好了,先根据移动距离判断是listview上下滑动还是父控件左右滑动,如果是左右滑动则让listview的touch事件return true,不让他乱动,同时调用
snapToScreen()方法人为滚动,如果是listview滚动则在触发ACTION_UP之前不允许触发左右滑动事件(就看谁先满足滚动条件了),
至于随手指移动而缓慢滑动的方式大家可以尝试一下,应该也是可以的,下面贴代码。
class ontouchlistener implements OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
//
listview.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
//
BaseTools.Log(TAG, "touchlisview", 1);
//
((HuicuiMusic)context).mScrollLayout.snapToScreen(1);
final int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
BaseTools.Log(TAG, "Acttion down", 2);
startPoint.set((int)event.getX(), (int)event.getY());
relevantListView = false;
break;
case MotionEvent.ACTION_MOVE:
movePoint.set((int)event.getX(), (int)event.getY());
BaseTools.Log(TAG, "X:" + Math.abs(movePoint.x - startPoint.x) + ";Y:" + Math.abs(movePoint.y - startPoint.y), 1);
if(!focusInListView && startPoint.x - movePoint.x > 60){
((HuicuiMusic)context).mScrollLayout.snapToScreen(1);
relevantListView = true;
return true;
}
if(Math.abs(movePoint.y - startPoint.y) > 60){
focusInListView = true;
return false;
}
break;
case MotionEvent.ACTION_UP:
focusInListView = false;
break;
}
if(relevantListView){
return true;
}else
return false;
}
}
给listview设置这个listener就OK了。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
现在ViewPager就能解决这种问题了吧,难点也不过是listView和ViewPager的焦点问题都很好解决,唉,当初那是得有多累。。。。不过编程思想可以拿来借鉴。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
现在ViewPager就能解决这种问题了吧,难点也不过是listView和ViewPager的焦点问题都很好解决,唉,当初那是得有多累。。。。不过编程思想可以拿来借鉴。