我正在使用Mike Ortiz的TouchImageView。
在其中,canScrollHorizontally
被覆盖:
@Override
public boolean canScrollHorizontally(int direction) {
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (getImageWidth() < viewWidth) {
return false;
} else if (x >= -1 && direction < 0) {
return false;
} else if (Math.abs(x) + viewWidth + 1 >= getImageWidth() && direction > 0) {
return false;
}
return true;
}
这可以按预期工作。我可以将TouchImageView放在ViewPager
中,并围绕缩放的图像滚动,但当我到达图像的边缘时,也可以向右/向左滑过ViewPager。
但我打算拥有一个嵌套在常规ViewPager中的垂直ViewPager。垂直ViewPager是在this SO post:
之后建模的public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev){
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev); // return touch coordinates to original reference frame for any child views
return intercepted;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
使用常规的ImageView,效果很好。我可以向左/向右滑动水平ViewPager,同时根据需要在嵌套的ViewPager中垂直滚动。垂直ViewPager的一个修改(允许从垂直ViewPager中的任何位置水平滚动)是:
@Override
public boolean canScrollHorizontally(int direction) {
return false;
}
小变化,效果很好。
当垂直ViewPager的内容是自定义TouchImageViews时,就会出现问题。右/左滑动仍然可以很好地工作,但垂直滑动仅在图像的右边缘与设备屏幕的右侧对齐时才起作用。这是由于TouchImageView类中的canScrollHorizontally
覆盖。
int direction
参数不考虑x或y。正y滑动与正x滑动无法区分。
我想要做的是覆盖canScrollVertically
方法,以检测何时发生垂直滑动,但从不调用该方法。即使只是一个快速测试,如:
@Override
public boolean canScrollVertically(int direction) {
matrix.getValues(m);
Toast.makeText(context, "vertical", Toast.LENGTH_SHORT).show();
return true;
}
永远不会打电话给。在canScrollHorizontally
方法中放置相同的Toast消息会在每次滑动(水平或垂直)上显示消息。
为什么canScrollVertically
从未被调用?
我想在视图中检测到图像何时触底,以及当用户向上滑动时。当满足这两个条件时,我可以从canScrollHorizontally
返回 false ,并允许垂直ViewPager正确滚动。
提前感谢您的帮助。有人都知道Mike Ortiz!?
答案 0 :(得分:0)
我提出的解决方案如下:
在TouchImageView
内,Mike有一个自定义类
private class PrivateOnTouchListener implements OnTouchListener
具有以下块:
case MotionEvent.ACTION_MOVE:
if (state == State.DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
... etc ...
}
break;
我所做的是设置全局boolean verticalDrag;
。使用上面的块,我检查以确保deltaY足够大于deltaX(即垂直拖动/滑动)
if(Math.abs(deltaY) > (Math.abs(deltaX) * sensitivity)){
verticalDrag = true;
}else{
verticalDrag = false;
}
敏感度由编码人员自行决定。真正的垂直滑动通常会有几个像素左/右偏差 - 难以仅在一个方向或另一个方向上滑动。因此,灵敏度可能相当高(即5到10或更高,具体取决于测试),它仍然会发射。
回到canScrollHorizontally
方法,我只需添加:
float y = m[Matrix.MTRANS_Y];
else if(Math.abs(y) + viewHeight + 1 >= getImageHeight() && verticalDrag){
return false;
}
允许垂直ViewPager根据需要滑动。
答案 1 :(得分:0)
就我而言,我正在检查我的scrollView(其中包含文本)在活动初始化时是否可以垂直滚动 。在手机上,它可以滚动,但在平板电脑上则不能。 canScrollVertically
返回了我不正确的值,因为尚无法确定。我通过在OnGlobalLayoutListener
中对其进行了调用来解决此问题。
(科特琳)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
// Must use onGlobalLayout or else canScrollVertically will not return the correct value because the layout hasn't been made yet
scrollView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
// If the scrollView can scroll, disable the accept menu item button
if ( scrollView.canScrollVertically(1) || scrollView.canScrollVertically(-1) )
acceptMenuItem?.isEnabled = false
// Remove itself after onGlobalLayout is first called or else it would be called about a million times per second
scrollView.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
}
我的用例正在显示使用条款。在用户滚动到底部之前,我不希望启用接受按钮。我知道已经晚了,但是我希望这可以解决关于canScrollVertically