在写自动化代码的时候对于listview的拖动有时候效果不尽人意,例如robotium自带的滚动操作scrollListToLine,最终的核心就是:
inst.runOnMainSync(new Runnable(){
public void run(){
view.setSelection(lineToMoveTo);
}
});
那么也就是说这样滚动其实最终是根据listview的item高度决定滚动的距离,那么我想每次只想滚动y距离怎么做。根据android-19的AbsListView中我们会发现一个方法:
/**
* Scrolls the list items within the view by a specified number of pixels.
*
* @param y the amount of pixels to scroll by vertically
* @see #canScrollList(int)
*/
public void scrollListBy(int y) {
trackMotionScroll(-y, -y);
}
实际上直接调用此方法是可以解决拖动指定listview垂直距离,但是前提是android-19(至于18有没有我不确定,17是没有的),所以通用性不强,不适合大部分平台,但是可以发现方法:
/**
* Track a motion scroll
*
* @param deltaY Amount to offset mMotionView. This is the accumulated delta since the motion
* began. Positive numbers mean the user's finger is moving down the screen.
* @param incrementalDeltaY Change in deltaY from the previous event.
* @return true if we're already at the beginning/end of the list and have nothing to do.
*/
boolean trackMotionScroll(int deltaY, int incrementalDeltaY)
从android-10(再之前没有关注)就已经存在了,只不过是相对于包内访问的,那么接下来利用java反射即可调用这个方法,但是有一点需要注意的是因为此方法是ListView的父类的默认修饰符的方法,所以需要反射父类的方法。
/**
* scroll Vertical
* @param solo
* @param y 垂直滑动的距离
*/
public void scrollVertical(final ListView listView, Activity activity, final int y){
if(listView == null)
return;
activity.runOnUiThread(new Runnable() { //执行自动化测试的时候模拟滑动需要进入UI线程操作
@Override
public void run() {
invokeMethod(listView, "trackMotionScroll", new Object[]{-y, -y}, new Class[]{int.class, int.class});
}
});
}
/**
* 遍历当前类以及父类去查找方法,例子,写的比较简单
* @param object
* @param methodName
* @param params
* @param paramTypes
* @return
*/
public Object invokeMethod(Object object, String methodName, Object[] params, Class[] paramTypes){
Object returnObj = null;
if (object == null) {
return null;
}
Class cls = object.getClass();
Method method = null;
for (; cls != Object.class; cls = cls.getSuperclass()) { //因为取的是父类的默认修饰符的方法,所以需要循环找到该方法
try {
method = cls.getDeclaredMethod(methodName, paramTypes);
break;
} catch (NoSuchMethodException e) {
// e.printStackTrace();
} catch (SecurityException e) {
// e.printStackTrace();
}
}
if(method != null){
method.setAccessible(true);
try {
returnObj = method.invoke(object, params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return returnObj;
}
以上就是整个比较重要的代码,若要结合robotium使用,则可以写的传参更少些:
public void scrollVertical(final ListView listView, Activity activity, final int y){
.....
}
写成:
public void scrollVertical(Solo solo, final int y){
listViews = solo.xxx()//根据实际获取listview情况决定
solo.getCurrentActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
invokeMethod(listView, "trackMotionScroll", new Object[]{-y, -y}, new Class[]{int.class, int.class});
}
});
}
使用示例:
这里指定y为动态获取设备屏幕的高度:height/n,可以比较灵活的实现滚动操作(例如滚动一屏或者半屏)。