Quantcast
Channel: Embarcadero Community - Embarcadero Community
Viewing all articles
Browse latest Browse all 3212

how to make bidi in fmx(firemonkey) text android ?

$
0
0
https://github.com/FMXExpress/android-object-pascal-wrapper/blob/c72e8dd237e4bb5a58e7c443680711ee75c4e8c0/android-n/java.text.Bidi.pas

 

type
JBidi = interface;
 
JBidiClass = interface(JObjectClass)
['{13A6E568-7932-4C20-A118-DA405698BC73}']
function _GetDIRECTION_DEFAULT_LEFT_TO_RIGHT : Integer; cdecl; // A: $19
function _GetDIRECTION_DEFAULT_RIGHT_TO_LEFT : Integer; cdecl; // A: $19
function _GetDIRECTION_LEFT_TO_RIGHT : Integer; cdecl; // A: $19
function _GetDIRECTION_RIGHT_TO_LEFT : Integer; cdecl; // A: $19
function baseIsLeftToRight : boolean; cdecl; // ()Z A: $1
function createLineBidi(lineStart : Integer; lineLimit : Integer) : JBidi; cdecl;// (II)Ljava/text/Bidi; A: $1

https://github.com/FMXExpress/android-object-pascal-wrapper/blob/c72e8dd237e4bb5a58e7c443680711ee75c4e8c0/android-n/android.icu.lang.UProperty.pas

https://uploadpie.com/9bSXLE

 

 

http://stackoverflow.com/questions/20473657/android-mixed-language-text-bidiformatter-on-string-with-rtl-and-ltr-text

There may be cases when mixed-language text is not to be shown in a TextView. For instance, the text may be passed in a share Intent to Gmail or WhatsApp and so on. In such cases, you must use a combination of the following classes:

 

 

As quoted in the documentation, these are ...

 

Utility class[es] for formatting text for display in a potentially opposite-directionality context without garbling. The directionality of the context is set at formatter creation and the directionality of the text can be either estimated or passed in when known.

 

So for example, say you have a String that has a combination of English & Arabic, and you need the text to be

 

  • right-to-left (RTL).
  • always right-aligned, even if the sentence begins with English.
  • English & Arabic words in the correct sequence and without garbling.

 

then you could achieve this using the unicodeWrap() method as follows:

 

String mixedLanguageText = ... // mixed-language text

if(BidiFormatter.getInstance().isRtlContext()){
    Locale rtlLocale = ... // RTL locale
    mixedLanguageText = BidiFormatter.getInstance(rtlLocale).unicodeWrap(mixedLanguageText, TextDirectionHeuristics.ANYRTL_LTR);
}

 

This would convert the string into RTL and align it to the left, if even one RTL-language character was in the string, and fallback to LTR otherwise. If you want the string to be RTL even if it is completely in, say English (an LTR language), then you could use TextDirectionHeuristics.RTL instead of TextDirectionHeuristics.ANYRTL_LTR.

 

This is the proper way of handling mixed-direction text in the absence of a TextView. Interestingly, as the documentation states,

 

Also notice that these direction heuristics correspond to the same types of constants provided in the View class for setTextDirection(), such as TEXT_DIRECTION_RTL.

https://github.com/FMXExpress/android-object-pascal-wrapper/blob/c72e8dd237e4bb5a58e7c443680711ee75c4e8c0/android-n/android.text.BidiFormatter.pas

type
JBidiFormatter = interface;
 
JBidiFormatterClass = interface(JObjectClass)
['{521D27F4-1112-4E47-811B-9624C6876759}']
function getInstance : JBidiFormatter; cdecl; overload; // ()Landroid/text/BidiFormatter; A: $9
function getInstance(locale : JLocale) : JBidiFormatter; cdecl; overload; // (Ljava/util/Locale;)Landroid/text/BidiFormatter; A: $9
function getInstance(rtlContext : boolean) : JBidiFormatter; cdecl; overload;// (Z)Landroid/text/BidiFormatter; A: $9
function getStereoReset : boolean; cdecl; // ()Z A: $1
function isRtl(str : JString) : boolean; cdecl; // (Ljava/lang/String;)Z A: $1
function isRtlContext : boolean; cdecl; // ()Z A: $1
function unicodeWrap(str : JString) : JString; cdecl; overload; // (Ljava/lang/String;)Ljava/lang/String; A: $1
function unicodeWrap(str : JString; heuristic : JTextDirectionHeuristic) : JString; cdecl; overload;// (Ljava/lang/String;Landroid/text/TextDirectionHeuristic;)Ljava/lang/String; A: $1
function unicodeWrap(str : JString; heuristic : JTextDirectionHeuristic; isolate : boolean) : JString; cdecl; overload;// (Ljava/lang/String;Landroid/text/TextDirectionHeuristic;Z)Ljava/lang/String; A: $1
function unicodeWrap(str : JString; isolate : boolean) : JString; cdecl; overload;// (Ljava/lang/String;Z)Ljava/lang/String; A: $1
end;

 

https://github.com/FMXExpress/android-object-pascal-wrapper/blob/c72e8dd237e4bb5a58e7c443680711ee75c4e8c0/android-n/android.icu.lang.UCharacter.pas

function getBidiPairedBracket(c : Integer) : Integer; cdecl; // (I)I A: $9
function getCharFromExtendedName(&name : JString) : Integer; cdecl; // (Ljava/lang/String;)I A: $9
function getCharFromName(&name : JString) : Integer; cdecl; // (Ljava/lang/String;)I A: $9
function getCharFromNameAlias(&name : JString) : Integer; cdecl; // (Ljava/lang/String;)I A: $9
https://github.com/FMXExpress/android-object-pascal-wrapper/blob/c72e8dd237e4bb5a58e7c443680711ee75c4e8c0/android-15/java.awt.font.TextAttribute.pas
type
JTextAttribute = interface;
 
JTextAttributeClass = interface(JObjectClass)
['{6A24F43C-4306-4E04-B049-09A968640356}']
function _GetBACKGROUND : JTextAttribute; cdecl; // A: $19
function _GetBIDI_EMBEDDING : JTextAttribute; cdecl; // A: $19
function _GetCHAR_REPLACEMENT : JTextAttribute; cdecl; // A: $19

 

http://stackoverflow.com/questions/29030977/how-to-draw-bidi-text-in-custom-view-using-staticlayout

In a custom android View I'm painting several user input texts that may be Bi-Directional. For example Hebrew or Arabic mixed with English text or numbers. To draw the text I basically use the view's Canvas, a TextPaint and a StaticLayout. The actual code is rather complex and spread out, but the bit that paints the text looks like so:

TextPaint _paint = getPaint();
Canvas _canvas = ...; // the canvas passed in the View.onDraw(Canvas canvas) method
PointF l = locationCenter(); // the location at which the center of text should be painted
int alignment = getAlignment(); // for this element, can vary for each element.
PointF textSize = getTextBounds(); // the bounding box of the text
String text = userInputText(); // actually some user input BiDi text
                switch (alignment) {
                    case 0:
                        _paint.setTextAlign(Paint.Align.CENTER);
                        l.x += textSize.x / 2.0f;
                        break;
                    case 1:
                        _paint.setTextAlign(Paint.Align.LEFT);
                        l.x -= 1;
                        break;
                    default:
                        _paint.setTextAlign(Paint.Align.RIGHT);
                        l.x += (textSize.x + 1);
                        break;
                }

                StaticLayout layout = new StaticLayout(text, _paint, (int) Math.ceil(textSize.x + 0.5f), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
                _canvas.translate(l.x, l.y);
                layout.draw(_canvas);
                _canvas.translate(-l.x, -l.y);

This works OK for LTR or RTL only text, but not for Bidi text which appears garbled. The odd thing is that when I force alignment to be 0 (resulting in _paint.setTextAlign(Paint.Align.Left) it usually seems to work OK (=as far as I can test). However, making alignment conditionnally 0 when text contains BiDi (or RTL) characters, does not work. It seems either Canvas, Paint or StaticLayout is preserving state.

I tried using a BidiFormatter like so:

                BidiFormatter.Builder builder = new BidiFormatter.Builder();
                builder.stereoReset(true);
                android.support.v4.text.BidiFormatter formatter = builder.build();
                String text = formatter.unicodeWrap(userInputText());
                // proceed as above

But that makes no difference (still garbled text).

Any idea how to reliably paint (many) BiDi texts in a custom view? And any idea why forcing alignment to Paint.Align.Left for all texts would seem to fix the problem. This should preferrably work from android 4.0 onwards, but at least 4.2 or 4.4. Thanks in advance.

I got it more or less working by using Character.getDirectionality to test for rtl chars in a text:

public static boolean containsRtlChar(String text) {
    for (int i = 0; i < text.length(); i++) {
        int c = text.codePointAt(i);
        int direction = Character.getDirectionality(c);
        if ((direction == Character.DIRECTIONALITY_RIGHT_TO_LEFT) || (direction == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) || (direction == Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING) || (direction == Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE))
            return true;
    }
    return false;
}

and then based on that force alignment to Left (

                if (containsRtlChars(text)) {
                    alignment = TextStyle.textAlignLeft;
                }

This results in text containing a RTL char to be OK, although with a fixed (center) alignment.

https://uploadpie.com/8yvheu
 
 
https://uploadpie.com/FqF3IQ
 

Viewing all articles
Browse latest Browse all 3212

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>