Update
RecyclerViews have a horizontal layout. So it is relatively easy to put a Vertical Mongolian TextView inside one of these. Here is an example from mongol-library
.
See this answer for a general solution to using a RecyclerView
to make a horizontally scrolling list.
Old answer
It is quite unfortunate that horizontal ListViews are not provided by the Android API. There are a number of StackOverflow Q&As that talk about how to do them, though. Here are a couple samples:
But when I actually tried to implement these suggestions as well as incorporate Mongolian vertical text, I was having a terrible time. Somewhere in my search I found a slightly different answer. It was a class that rotated an entire layout. It did so by extending ViewGroup. In this way anything (including a ListView) can be put in the ViewGroup and it gets rotated. All the touch events work, too.
As I explained in my answer about Mongolian TextViews, it is not enough to simply rotate Mongolian text. That would be enough if every ListView item (or other text element in the ViewGroup) was only a single line, but rotating multiple lines make the line wrap go the wrong direction. However, mirroring the layout horizontally and also using a vertically mirrored font can overcome this, as is shown in the following image.
I adapted the rotated ViewGroup code to also do the horizontal mirroring.
public class MongolViewGroup extends ViewGroup {
private int angle = 90;
private final Matrix rotateMatrix = new Matrix();
private final Rect viewRectRotated = new Rect();
private final RectF tempRectF1 = new RectF();
private final RectF tempRectF2 = new RectF();
private final float[] viewTouchPoint = new float[2];
private final float[] childTouchPoint = new float[2];
private boolean angleChanged = true;
public MongolViewGroup(Context context) {
this(context, null);
}
public MongolViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
}
public View getView() {
return getChildAt(0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final View view = getView();
if (view != null) {
measureChild(view, heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(resolveSize(view.getMeasuredHeight(), widthMeasureSpec),
resolveSize(view.getMeasuredWidth(), heightMeasureSpec));
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (angleChanged) {
final RectF layoutRect = tempRectF1;
final RectF layoutRectRotated = tempRectF2;
layoutRect.set(0, 0, right - left, bottom - top);
rotateMatrix.setRotate(angle, layoutRect.centerX(), layoutRect.centerY());
rotateMatrix.postScale(-1, 1);
rotateMatrix.mapRect(layoutRectRotated, layoutRect);
layoutRectRotated.round(viewRectRotated);
angleChanged = false;
}
final View view = getView();
if (view != null) {
view.layout(viewRectRotated.left, viewRectRotated.top, viewRectRotated.right,
viewRectRotated.bottom);
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
canvas.rotate(-angle, getWidth() / 2f, getHeight() / 2f);
canvas.scale(-1, 1);
super.dispatchDraw(canvas);
canvas.restore();
}
@Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
invalidate();
return super.invalidateChildInParent(location, dirty);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
viewTouchPoint[0] = event.getX();
viewTouchPoint[1] = event.getY();
rotateMatrix.mapPoints(childTouchPoint, viewTouchPoint);
event.setLocation(childTouchPoint[0], childTouchPoint[1]);
boolean result = super.dispatchTouchEvent(event);
event.setLocation(viewTouchPoint[0], viewTouchPoint[1]);
return result;
}
}
The Mongolian vertically mirrored font still needs to be set somewhere else, though. I find it easiest to make a custom TextView to do it:
public class MongolNonRotatedTextView extends TextView {
// This class does not rotate the textview. It only displays the Mongol font.
// For use with MongolLayout, which does all the rotation and mirroring.
// Constructors
public MongolNonRotatedTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MongolNonRotatedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MongolNonRotatedTextView(Context context) {
super(context);
init();
}
// This class requires the mirrored Mongolian font to be in the assets/fonts folder
private void init() {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(),
"fonts/MongolMirroredFont.ttf");
setTypeface(tf);
}
}
Then the custom ListView item xml layout can look something like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rlListItem"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.MongolNonRotatedTextView
android:id="@+id/tvListViewText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
Known issues:
- If you look carefully at the image below you can see faint horizontal and vertical lines around the text. Although this image comes from another developer's app, I am getting the same artifacts in my app when I use the rotated ViewGroup (but not when I use the rotated TextView). If anyone knows where these are coming from, please leave me a comment!
- This solution does not deal with rendering the Unicode text. Either you need to use non-Unicode text (discouraged) or you need to include a rendering engine in your app. (Android does not support OpenType smartfont rendering at this time. Hopefully this will change in the future. iOS, by comparison does support complex text rendering fonts.) See this link for a Unicode Mongolian rendering engine example.