Recently, we have started adding support for Arabic - which needs RTL layouts. One of our screens uses a 2D scroller, which I found here:
But, when we switch to RTL there are two problems:
childview
is cut offI've tried looking at the source code for Horizontal scrollview
- which handles rtl correctly. So far, I only saw two references to rtl in the code: during onLayout()
. When I try something similar though, my child view just disappears.
So far I could find no other solutions supporting both 2d scrolling and rtl. So, I'm hoping to resolve it here for me and for some future soul that needs something similar.
Ok, so put this together from a whole bunch of different solutions:
Create two custom components, one extending ScrollView and the other extending Horizontal Scroll View:
public class VScroll extends ScrollView {
public VScroll(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VScroll(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VScroll(Context context) {
super(context);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
}
AND
public class HScroll extends HorizontalScrollView {
public HScroll(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public HScroll(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HScroll(Context context) {
super(context);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
}
in the activity where you need the '2d scroller', use the following: in OnCreate():
vScroll = findViewById(R.id.vScroll);
hScroll = findViewById(R.id.hScroll);
and then
private VelocityTracker mVelocityTracker;
private float mx, my;
private float curX, curY;
private boolean started;
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
curX = event.getX();
curY = event.getY();
int dx = (int) (mx - curX);
int dy = (int) (my - curY);
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
if (started) {
vScroll.smoothScrollBy(0, dy);
hScroll.smoothScrollBy(dx, 0);
} else {
started = true;
}
mx = curX;
my = curY;
break;
case MotionEvent.ACTION_UP:
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000);
int initialXVelocity = (int) velocityTracker.getXVelocity();
int initialYVelocity = (int) velocityTracker.getYVelocity();
vScroll.fling(-initialYVelocity);
hScroll.fling(-initialXVelocity);
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
return true;
}
This allows for bi-directional scrolling (yes, even diagonal) as well as some velocity to allow for the 'fling' effect. Best of all, it works nicely with RTL and LTR layouts! Hope this is useful for someone else out there too....
EDIT: Forgot to add the XML part:
<pack.customcomponents.VScroll android:layout_height="fill_parent"
android:layout_width="fill_parent" android:id="@+id/vScroll">
<pack.customcomponents.HScroll android:id="@+id/hScroll"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:id="@+id/view_to_scroll"/>
</pack.customcomponents.HScroll>
</pack.customcomponents.VScroll>