/* Copyright (c) 2011-2013 Tang Ke
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.aretha.slidemenu.utils;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.webkit.WebView;
import android.widget.HorizontalScrollView;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.WeakHashMap;
/**
* Provide base implements of {@link ViewPager}, {@link HorizontalScrollView},
* {@link WebView} scroll detect, You can use {@link ScrollDetectorFactory} to
* add your own implements of {@link ScrollDetector}
*
* @author Tank
*/
public class ScrollDetectors {
private static final WeakHashMap<Class<? extends View>, ScrollDetector> IMPLES = new WeakHashMap<Class<? extends View>, ScrollDetector>();
private static ScrollDetectorFactory mFactory;
/**
* Check the view is horizontal scrollable
*
* @param v
* @param direction
* @return
*/
public static boolean canScrollHorizontal(View v, int direction) {
ScrollDetector imples = getImplements(v);
if (null == imples) {
return false;
}
return imples.canScrollHorizontal(v, direction);
}
/**
* Check the view is vertical scrollable
*
* @param v
* @param direction
* @return
*/
public static boolean canScrollVertical(View v, int direction) {
ScrollDetector imples = getImplements(v);
if (null == imples) {
return false;
}
return imples.canScrollVertical(v, direction);
}
private static ScrollDetector getImplements(View v) {
Class<? extends View> clazz = v.getClass();
ScrollDetector imple = IMPLES.get(clazz);
if (null != imple) {
return imple;
}
if (v instanceof ViewPager) {
imple = new ViewPagerScrollDetector();
} else if (v instanceof HorizontalScrollView) {
imple = new HorizontalScrollViewScrollDetector();
} else if (v instanceof WebView) {
imple = new WebViewScrollDetector();
} else if (null != mFactory) {
imple = mFactory.newScrollDetector(v);
} else {
return null;
}
IMPLES.put(clazz, imple);
return imple;
}
/**
* Base implements of {@link ScrollDetector} for {@link ViewPager}
*
* @author Tank
*/
private static class ViewPagerScrollDetector implements ScrollDetector {
@Override
public boolean canScrollHorizontal(View v, int direction) {
ViewPager viewPager = (ViewPager) v;
PagerAdapter pagerAdapter = viewPager.getAdapter();
if (null == pagerAdapter || 0 == pagerAdapter.getCount()) {
return false;
}
final int currentItem = viewPager.getCurrentItem();
return (direction < 0 && currentItem < pagerAdapter.getCount() - 1)
|| (direction > 0 && currentItem > 0);
}
@Override
public boolean canScrollVertical(View v, int direction) {
// TODO
return false;
}
}
/**
* Base implements of {@link ScrollDetector} for {@link WebView}
*
* @author Tank
*/
private static class WebViewScrollDetector implements ScrollDetector {
@Override
public boolean canScrollHorizontal(View v, int direction) {
try {
// Because this method is protected
Method computeHorizontalScrollOffsetMethod = WebView.class
.getDeclaredMethod("computeHorizontalScrollOffset");
Method computeHorizontalScrollRangeMethod = WebView.class
.getDeclaredMethod("computeHorizontalScrollRange");
computeHorizontalScrollOffsetMethod.setAccessible(true);
computeHorizontalScrollRangeMethod.setAccessible(true);
final int horizontalScrollOffset = (Integer) computeHorizontalScrollOffsetMethod
.invoke(v);
final int horizontalScrollRange = (Integer) computeHorizontalScrollRangeMethod
.invoke(v);
return (direction > 0 && v.getScrollX() > 0)
|| (direction < 0 && horizontalScrollOffset < horizontalScrollRange
- v.getWidth());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean canScrollVertical(View v, int direction) {
// TODO
return false;
}
}
/**
* Base implements of {@link ScrollDetector} for
* {@link HorizontalScrollView}
*
* @author Tank
*/
private static class HorizontalScrollViewScrollDetector implements
ScrollDetector {
@Override
public boolean canScrollHorizontal(View v, int direction) {
HorizontalScrollView horizontalScrollView = (HorizontalScrollView) v;
final int scrollX = horizontalScrollView.getScrollX();
// Without scroll wrapper, can't scroll
if (0 == horizontalScrollView.getChildCount()) {
return false;
}
return (direction < 0 && scrollX < horizontalScrollView.getChildAt(
0).getWidth()
- horizontalScrollView.getWidth())
|| (direction > 0 && scrollX > 0);
}
@Override
public boolean canScrollVertical(View v, int direction) {
// TODO
return false;
}
}
/**
* Factory for create new scroll detector
*
* @param factory
*/
public static void setScrollDetectorFactory(ScrollDetectorFactory factory) {
mFactory = factory;
}
/**
* @author Tank
*/
public interface ScrollDetector {
public boolean canScrollHorizontal(View v, int direction);
public boolean canScrollVertical(View v, int direction);
}
}