ã¯ããã«
ãMyOfficeãã¯ææ°ã®ã»ãšãã©ã®ãã©ãããã©ãŒã ã§åäœããŸããWindowsãMacOSãLinuxåãã®Webã¯ã©ã€ã¢ã³ãããã¹ã¯ãããããŒãžã§ã³ãiOSãAndroidãTizenåãã®ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã§ãã ãŸããé·ãéã³ã³ãã¥ãŒã¿ãŒã¢ããªã±ãŒã·ã§ã³ãéçºããéã«ã¯ãã€ã³ã¿ãŒãã§ã€ã¹èšèšã«ã¢ãããŒãããããã®åºæ¬çãªã«ãŒã«ããããŸãããã¢ãã€ã«ããã€ã¹çšã®ã¢ããªã±ãŒã·ã§ã³ãäœæããå Žåã¯ãå€ãã®æ©èœãåå¥ã«æ€èšããå¿ èŠããããŸãã

ããã¹ããšãã£ã¿ãŒã®éçºæã«ãæšæºã®EditTextãæŸæ£ããTextureViewã³ã³ããŒãã³ãã«åºã¥ããŠããã¹ããå ¥åããã³æžåŒèšå®ããããã®ã³ã³ããŒãã³ããå®è£ ããŸããã æšæºã®ã¡ã«ããºã ã§ã¯ãããŒãã«ãç»åã®è¿œå ãã¹ã¿ã€ã«ãè²ã®é©çšããªã¹ãã®æäœãã€ã³ãã³ããªã©ãã§ããŸããã§ããã ã³ã³ããŒãã³ãã䜿çšãããšãæ°ããæ©èœãè¿œå ããæè»æ§ãåŸãããã³ã³ããŒãã³ãã®ããã©ãŒãã³ã¹ãæé©åã§ããŸãã
ã³ã³ããŒãã³ãã®ã¿ã¹ã¯ã®1ã€ã¯ããŠãŒã¶ãŒãããŒããŒãããããŒã¿ãå ¥åããããã¹ããç·šéããèªå眮ææ©èœãšããã¹ãä¿®æ£ãé©çšã§ããããã«ããããšã§ãã 次ã«ãããŒããŒããšå¯Ÿè©±ããã«ã¹ã¿ã èŠçŽ ãå®è£ ããå ¥åãããããã¹ããååŸããããŒããŒãã«å€æŽãéä¿¡ããæ¹æ³ã説æããŸãã ã«ã¹ã¿ã ããŒããŒãã®äœæã¯ããã®èšäºã®ç¯å²å€ã§ãïŒ ãã¡ã ã ãã¡ãããŸãã¯ãã¡ããã芧ãã ãã ïŒã

CustomViewãšããŒããŒã
ViewèŠçŽ ãšããŒããŒãã®å¯Ÿè©±ã®ããã»ã¹å šäœã¯ã InputConnectionã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠè¡ãããŸãã Android SDKã«ã¯ãåºæ¬çãªå®è£ ãæ¢ã«ãããŸããBaseInputConnectionã䜿çšãããšãããŒããŒãããã€ãã³ããåä¿¡ããããããåŠçããŠãã³ã³ããŒãã³ãã«å¯ŸããŠåä¿¡ããããŒã¿ã®çµæã§ããEditableã€ã³ã¿ãŒãã§ãŒã¹ãšå¯Ÿè©±ã§ããŸãã
ããããé çªã«å§ããŸãããã ããŒããŒãã«æ¥ç¶ããã«ã¯ããŸããéçºãããã³ã³ããŒãã³ããšå¯Ÿè©±ããããã®ã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ã決å®ããå¿ èŠããããŸã-ããŒããŒãããã€ãã³ãããµãã¹ã¯ã©ã€ãããããã ããã«ãããŒããŒãã®çš®é¡ãšãã®åäœã«åœ±é¿ããå€ãã®èšå®ãããŒããŒãèªäœã«è»¢éã§ããŸãã ãã®ãããå®è£ ãè¿ãã³ã³ããŒãã³ãã¡ãœããonCreateInputConnectionïŒ...ïŒããªãŒããŒã©ã€ãããå¿ èŠããããŸãã å€æŽå¯èœãªããŒããŒããã©ã¡ãŒã¿ã¯å±æ§ãšããŠæäŸãããŸãã
@Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { // outAttrs.inputType = InputType.TYPE_CLASS_TEXT; outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE; outAttrs.initialSelEnd = outAttrs.initialSelStart = 0; // return new BaseInputConnection(this, true); }
æå®ãããäŸã§ã¯ãã¡ãœããã¯ã€ã³ã¿ãŒãã§ã€ã¹ã®åºæ¬å®è£ ãè¿ããŸãã ãŸããEditorInfoã¯ããŒããŒãã®ãã©ã¡ãŒã¿ãŒãæå®ããŸãã ããã®ããã¥ã¡ã³ãã§ã©ã®ãã®ãèŠã€ãããã«ã€ããŠã ããšãã°ã inputTypeã䜿çšããŠãããŒããŒãã®æ°å€ãŸãã¯ããã¹ãå ¥åãæå®ã§ããŸãã
inputTypeã«å€TYPE_NULL ãæž¡ããšããœãããŠã§ã¢ããŒããŒãã®èªåããŒããŒããç¡å¹ã«ãªãããã¹ãŠã®ã€ãã³ãã衚瀺ãããããšã«æ³šæããŠãã ãã ã onKeyDown ïŒããã³ç©çã§äœæ¥ãããšãïŒã
ãã§ã«è¡šç€ºãããŠããããŒããŒãæ§æãå€æŽããå¿ èŠãããå ŽåïŒããšãã°ãå ¥åã¿ã€ããå€æŽãããå ŽåïŒã restartInputã¡ãœãããåŒã³åºãå¿ èŠããããŸãã ãã®å ŽåãonCreateInputConnectionãå床åŒã³åºãããæ°ããå€ãEditorInfoã«æž¡ãããšãã§ããŸãã ãã ããããã«ããInputConnectionèªäœãåäœæãããããšãèæ ®ããå¿ èŠããããŸãã
次ã®ã¹ãããã§ã¯ã setFocusableInTouchMode ïŒtrueïŒã¡ãœãããåŒã³åºããŸãïŒããšãã°ã onFinishInflate ïŒïŒã¡ãœããããããŸãã¯ããŒã¯ã¢ããã§å±æ§ã䜿çšããŸã ïŒã ããã«ãããã³ã³ããŒãã³ãã¯ãã©ãŒã«ã¹ãã€ã³ã¿ãŒã»ããã§ããããšã瀺ããŸãã ãŸããããŒããŒããšã®å¯Ÿè©±ã¯ãçŸåšãã©ãŒã«ã¹ãããŠããèŠçŽ ã§ã®ã¿å¯èœã§ãã ãããè¡ãããªãå ŽåãonCreateInputConnectionã¡ãœããã¯åŒã³åºãããŸããã
@Override protected void onFinishInflate() { super.onFinishInflate(); setFocusableInTouchMode(true); ... }
ããã«ãã³ã³ããŒãã³ããæŒããšãã¯ãããŒããŒããéãå¿ èŠãããããšã«æ³šæããŠãã ããã ããã¯èªåçã«ã¯è¡ãããªããããããã«æ³šæããå¿ èŠããããŸãã ãããè¡ã1ã€ã®ãªãã·ã§ã³ïŒ
setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(v, 0); } });
æåŸã«è¡ãããšã¯ã onCheckIsTextEditorã¡ãœããããªãŒããŒã©ã€ããã TRUE ïŒããã©ã«ãã§ã¯falseïŒãè¿ãããšã§ãã ããã¥ã¡ã³ãã«ãããšãããã¯ã·ã¹ãã ãããŒããŒããç»é¢ã«èªåçã«è¡šç€ºããããã®ãã³ãã§ãã
public class CustomView extends View { ... @Override public boolean onCheckIsTextEditor() { return true; } ⊠}
ãã®çµæãããŒããŒããšã®çžäºäœçšã確ç«ããã«ã¯ã以äžãè¡ãå¿ èŠããããŸãã
1. onCreateInputConnectionã¡ãœããããªãŒããŒã©ã€ãããŠã察話ã€ã³ã¿ãŒãã§ãŒã¹ã®å®è£ ãšããŒããŒãã®ãã©ã¡ãŒã¿ãŒã瀺ããŸãã
2.ã³ã³ããŒãã³ããåæåããããšãã«setFocusableInTouchMode ïŒtrueïŒãåŒã³åºããŸãã
3. imm.showSoftInputïŒ...ïŒãåŒã³åºããŠãã³ã³ããŒãã³ããæŒãããšãã«ããŒããŒãã衚瀺ããŸãã
4. onCheckIsTextEditorã¡ãœããã§TRUEãè¿ããŸãã
ããã§ãããŒããŒãããã€ãã³ãã®åä¿¡ãéå§ããæ¹æ³ã説æãããŸããã 次ã«ããããã®ã€ãã³ãã®åŠçæ¹æ³ã«ã€ããŠèª¬æããŸãã
å ¥åæ¥ç¶
以åãAndroid SDKã«ã¯InputConnectionã€ã³ã¿ãŒãã§ãŒã¹ã®åºæ¬å®è£ ã§ããBaseInputConnectionãããããšã«æ³šæãããŸããã ããŒããŒããšå¯Ÿè©±ããåä¿¡ããã€ãã³ããç·šéå¯èœãªãªããžã§ã¯ãã«å§ä»»ã§ããåºæ¬çãªããžãã¯ãè¿œå ããŸããããã«ãããã«ã¹ã¿ã ã³ã³ããŒãã³ããä»åŸåäœããããã«ãªããŸãã éçºã®ããã«ã ããããç¶æ¿ããŠgetEditable ïŒïŒã¡ãœããããªãŒããŒã©ã€ãããããã«Editableå®è£ ãæž¡ãããšããå§ãããŸãã
public class TestInputConnection extends BaseInputConnection { ... @Override public Editable getEditable() { return mCustomView.getEditable(); } ... }
ç·šéå¯èœã€ã³ã¿ãŒãã§ã€ã¹ã®è©³çŽ°ã«ã€ããŠã¯ã以äžã§èª¬æããŸãã ãããŸã§ã®éã誰ãã«åœ¹ç«ã€ãããããªãInputConnectionã¡ãœãããããã€ãèããããšæããŸãã ãã¹ãŠã®ã¡ãœããã®å®å šãªããã¥ã¡ã³ãã¯ã ããã§èŠã€ããããšãã§ããŸã ã ã¡ãœããåŒã³åºãã®ã·ãŒã±ã³ã¹ãåŒã³åºããããã©ã¡ãŒã¿ãŒã®å€ã¯ãããã€ã¹ãžã®å ¥åæã«äœ¿çšãããããŒããŒãã®å®è£ ã«äŸåããç°ãªãå Žåãããããšã«æ³šæããŠãã ããã
beginBatchEditïŒïŒããã³endBatchEditïŒïŒ
ããŒããŒãããã®äžé£ã®ã¢ã¯ã·ã§ã³ã®éå§ãšçµäºã«ã€ããŠéç¥ããŸãã ããšãã°ãT9ã¢ãŒãã®ããŒããŒãã§ã¯ãããã¹ãã®åŸã«ã¹ããŒã¹ãå ¥åãããŸãã ãã®å Žåã finishComposingTextïŒïŒããã³commitTextïŒïŒã®åŒã³åºãã¯ãåããããã€ãã³ãå ã§é çªã«çºçããŸãã ã€ãŸããã·ãŒã±ã³ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
beginBatchEdit
finishComposingText
beginBatchEdit
endBatchEdit
commitText
beginBatchEdit
endBatchEdit
endBatchEdit
ãããã®ãã¹ããèš±å¯ãããŠããããšã«æ³šæããŠãã ããã ã€ãŸããããã»ã¹ãçµäºãããã©ãããå€æããã«ã¯ãéå§ãããã³ãŒã«ã®æ°ãšçµäºããã³ãŒã«ã®æ°ãèæ ®ããå¿ èŠããããŸãã ããšãã°ã EditableInputConnectionã®å®è£ ïŒTextViewã®å®è£ ïŒãèŠãããšãã§ããŸãããã®å®è£ ã§ã¯ãéå§æã«å¢åãçºçããçµäºæã«æžåãçºçããŸãã
éèŠïŒ ããããçµäºãããŸã§ããšãã£ã¿ãŒããããŒããŒãã«ã€ãã³ããéä¿¡ããããšã¯ãå§ãããŸããïŒããšãã°ãã«ãŒãœã«äœçœ®ã®å€æŽïŒã
setComposingTextïŒïŒ
ãã®ã¡ãœããã¯ãããããè€åããã¹ããããŒããŒãããå ¥åããããšãã«åŒã³åºãããŸãã ããšãã°ãé³å£°å ¥åããªãŒãã³ã¬ã¯ãã¢ãŒãã§ã®ããã¹ãå ¥åãªã©ã ã€ãŸããããŒããŒãã§èª¿æŽ/眮æã§ããããã¹ãã
testãšããåèªãå ¥åããäŸïŒ
setComposingText t 1
setComposingText te 1
setComposingText tes 1
setComposingTextãã¹ã1
ã¡ãœããã®ãã©ã¡ãŒã¿ãŒãšããŠãè€åããã¹ãã®æ°ããå€ããããŸãã ããã«ããã®å€ã¯ç·šéå¯èœã«è»¢éãããç¹å¥ãªã¹ãã³ïŒããã¹ããæ§æããéå§ããã³çµäºããŒã¯ïŒã§ããŒã¯ãããŸãã æ°ããè€åããã¹ãããšã«ãããŒã¯ãããã¹ãã³ã«åŸã£ãŠä»¥åã®è€åããã¹ããåé€ãããŸãã ãããã£ãŠãèªå眮æããã¹ããçºçããŸãã
finishComposingTextïŒïŒ
ããã§ã¯ãã¹ãŠãéåžžã«ç°¡åã§ãããã®ã¡ãœããã¯ãããã¹ãããã以äžä¿®æ£ãããããŠãŒã¶ãŒã«ãã£ãŠæçµããŒãžã§ã³ãå ¥åããããšããŒããŒããå€æããæç¹ã§åŒã³åºãããŸãã åæã«ãããã¹ãã®äœæã«é¢ãããã¹ãŠã®æ å ±ãç·šéå¯èœããåé€ãããŸãã
commitTextïŒïŒ
è¿œå ãããããã¹ããæ¿èªããããšããã€ãŸã調æŽãèšç»ãããŠããªãå Žåã ã¡ãœããã¯ãã©ã¡ãŒã¿ãŒCharSequence text int newCursorPositionã䜿çšããŠåŒã³åºãããŸãã ããšãã°ãææ¡ã¯ããŒããŒãããéžæãããŸãã ãã®å Žåãããã¹ãã®å€ã衚瀺ãããŸãããã®å€ã¯ãçŸåšã®ã«ãŒãœã«ã®å Žæã«è¿œå ããå¿ èŠããããŸãïŒååšããå Žåã¯ãäœæããã¹ãã®ä»£ããã«ïŒã ãšãã£ã¿ãŒã®æ°ããã«ãŒãœã«äœçœ®ã«é¢ããæ å ±ãšåæ§ã å€> 0ïŒããšãã°ã1ïŒã¯ãæ°ããããã¹ãã®æåŸã®ã«ãŒãœã«ã®äœçœ®ã瀺ããŸãã ãã®ä»ã®æå³ã¯æåã«ãããŸãã

deleteSurroundingTextïŒïŒ
ãã®ã¡ãœããã¯ã2ã€ã®ãã©ã¡ãŒã¿ãŒïŒ int beforeLengthãint afterLengthïŒã§åŒã³åºãã ãçŸåšã®ã«ãŒãœã«äœçœ®ã®ååŸã®ããã¹ãã®äžéšãåé€ããå¿ èŠãããããšãéç¥ããŸãã ããã«ãããã¹ãã®éžæãããå Žåããããã®æåã¯ç¡èŠãããŸãã
ããšãã°ãT9ã¢ãŒãã®ãŠãŒã¶ãŒããšãã£ã¿ãŒã§ããã¹ããã¯ãªãã¯ããããã³ããã®ãªã¹ãããéžæããåèªã眮ãæãããšããã®ã¡ãœãããåŒã³åºãããŸãã
ç·šéå¯èœãªå®è£
BaseInputConnectionã¯ãEditableã€ã³ã¿ãŒãã§ãŒã¹ãšå¯æ¥ã«é£æºãããã®å®è£ ã¯getEditableïŒïŒã¡ãœããã§æž¡ãå¿ èŠããããŸãã ãã¹ãŠã®ã€ã³ã¿ãŒãã§ã€ã¹ã¡ãœããã¯ã3ã€ã®ã¿ã€ãã«åé¡ã§ããŸãã
*ããã¹ãã®å€æŽãšåä¿¡ã
*ã¹ãã³ã§åäœããŸãã
*ãã£ã«ã¿ãŒã®é©çšã
TextViewã®å®è£ ãèŠããšã getTextïŒïŒã¡ãœãããEditableãè¿ãããšãããããŸãã ããæ£ç¢ºã«ã¯ã SpannableStringBuilderå®è£ ã§ããããã¯ã¡ã€ã³ã§ãããããã¹ããä¿åããã³å€æŽãããã£ã«ã¿ããã³ã¹ãã³ãæäœããæºåãã§ããŠããŸãã
äœããã®çç±ã§æšæºå®è£ ãé©åã§ãªãå Žåã¯ãç¬èªã®å®è£ ãå¯èœã§ãã ããã¹ãã®å€æŽãæ±ãäž»ãªæ¹æ³ã¯replaceïŒ...ïŒã§ãã ãã¹ãŠã®æ¿å ¥ãè¿œå ãåé€ãªã© ç¹å®ã®ã»ã¯ã·ã§ã³ã®ããã¹ããæ°ãããã®ã«çœ®ãæããŸãã ãã ãã眮æããåã«ãããã¹ãã«äžé£ã®ãã£ã«ã¿ãŒãé©çšããå¿ èŠãããããšãå¿ããªãã§ãã ããã ããã«ãã«ãŒãœã«ã®äœçœ®ãããã¹ãã®éžæãæ§æé åïŒèªå眮æã®é åã®éå§ãšçµäºïŒãªã©ã®ã¿ã°ããã³ã°ã¢ããã§ããã¹ãã³ãæ£ããæäœããããšãéèŠã§ãã
ããã¹ããŠã©ããã£ãŒ
ããŒããŒãããã³æšæºã®Editableãšã®å¯Ÿè©±ã®æšæºçãªå®è£ ã«æºè¶³ããŠãããšããŸãããã éçºäžã®ã³ã³ããŒãã³ãã«æ»ããç·šéå¯èœãªå€æŽããµãã¹ã¯ã©ã€ãããŸãã ããã¯ã TextWatcherãªããžã§ã¯ãã«ç¹å¥ãªã¹ãã³ãè¿œå ããããšã§éåžžã«ç°¡åã«å®è¡ãããŸãã
mEditable.setSpan(mMyTextWatcher, 0, mEditable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
ãã®åŸãç·šéå¯èœãªå€æŽã«ã€ããŠã¯ãéç¥ãå±ããŸãã ãã©ã°-SPAN_INCLUSIVE_INCLUSIVEãæå®ããããšãéèŠã§ããããã«ããã clearSpansïŒïŒã¡ãœãããåŒã³åºããšãã«ãªã¹ããŒãåé€ã§ããªããªããŸãïŒããšãã°ãfinishComposingTextãçºçãããšãã«åŒã³åºãããŸãïŒã
éç¥ãåãåã£ããã次ã®æ å ±ãååŸã§ããŸãã
* mEditableã toStringïŒïŒã¯ãã¹ãŠã®ããã¹ããè¿ããŸãã UIã«è¡šç€ºã§ããŸã-ããã¯ãŠãŒã¶ãŒãå ¥åãããã®ã§ãã
*ã«ãŒãœã«ãšéžæã«é¢ããæ å ±ãååŸããã«ã¯ã Selectionã¯ã©ã¹ã®ã¡ãœãããå¿ èŠã§ãã

setTextïŒïŒ
ã³ã³ããŒãã³ãã«setTextïŒïŒã¡ãœããããããšããŸãã éçºããã³ã³ããŒãã³ãã®ç·šéå¯èœãªå€ãæŽæ°ããããŒããŒããããã¡ãŒå ã®åã®ããã¹ããç¡å¹ã§ããããšãããŒããŒãã«éç¥ããå¿ èŠããããŸãã ãããè¡ãã«ã¯ãæ°ããEditableãªããžã§ã¯ããäœæãã restartInputã¡ãœãããåŒã³åºããŸãã
public void setText(@NonNull String newText) { mEditable = Editable.Factory.getInstance().newEditable(newText); mImm.restartInput(this); }
ã«ãŒãœã«äœçœ®ãå€æŽãã
ããŒããŒããšå®å šã«å¯Ÿè©±ããã«ã¯ãã«ãŒãœã«äœçœ®ã®ãµããŒããè¿œå ããå¿ èŠããããŸãã setComposingTextïŒïŒããã³commitTextïŒïŒ ã¡ãœããã§ã®ããã¹ãå ¥åã®å Žåãå€ã¯cursorPositionãã©ã¡ãŒã¿ãŒã«å«ãŸããŸãããã®ãã©ã¡ãŒã¿ãŒã¯ãã«ãŒãœã«ãè¿œå ããããã¹ãã®å é ãŸãã¯æ«å°Ÿã«é 眮ãããã©ããã決å®ããŸãã BaseInputConnectionãä»ããå®è£ ã®å Žåãã«ãŒãœã«äœçœ®ã管çããå¿ èŠã¯ãããŸãããããžãã¯ã¯æ¢ã«å éšã«å®è£ ãããŠããŸãã Selectionã¡ãœããã䜿çšããã ãã§ååã§ãã getSelectionStartããã³getSelectionEndã䜿çšããŠäœçœ®ãèŠã€ããŸãã
ã«ãŒãœã«å€æŽã®åŸæ¹ãµããŒããè¿œå ããããšã¯éåžžã«éèŠã§ãã ããšãã°ãéçºäžã®ã³ã³ããŒãã³ããã«ãŒãœã«ã衚瀺ã§ãããã®äœçœ®ãå€æŽã§ããå Žåãå€æŽãããã³ã«ããŒããŒãã«éç¥ããå¿ èŠããããŸãã ãããè¡ãããªãå ŽåãããŒããŒãããã®åŸç¶ã®ããã¹ãå ¥åã¯ãå€æŽãããäœçœ®ãç¡èŠããŸãã ãŸããT9ã¢ãŒãã§ã®åèªã®çœ®æã¯æ£ããæ©èœããŸããã
éç¥ã®ããã«ããã³ã®æ°ããäœçœ®ã«é¢ããæ å ±ãéä¿¡ãããupdateSelectionã¡ãœããã䜿çšãããŸãã InputConnectionã®ããããçµäºãããŸã§ãéç¥ãéä¿¡ããªãããšãå¿ããªãã§ãã ããã
åèªãT9ã«çœ®ãæããŸã
ãŠãŒã¶ãŒãT9ã§ããŒããŒãã䜿çšããå Žåã®å°ããªäŸã§ãã ãšãã£ã¿ãŒã«ããã€ãã®åèªãå ¥åããããã®ãã¡ã®1ã€ãã¯ãªãã¯ããããšããŸãã æšæºã®EditTextã䜿çšããå ŽåãããŒããŒãã«ãã³ãã衚瀺ãããã¯ãªãã¯ãããšåèªãå®å šã«çœ®ãæããããŸãã

EditTextã䜿çšãããšãããŒããŒãã¯æ°ããã«ãŒãœã«äœçœ®ã«é¢ããæ å ±ãåãåãã setComposingRegionã¡ãœãããä»ããŠçŸåšéžæãããŠããäœæããã¹ãã«é¢ããæ å ±ããšãã£ã¿ãŒã«éãè¿ããŸã ãããã«ãããåŒãç¶ãåäœããåèªãã€ãŸãã«ãŒãœã«ã®äžã®åèªãããŒã¯ããŸãã ããã³ããã®1ã€ãéžæãããšãã¡ãœãããåŒã³åºãããŸããçŸåšã®åèªãåé€ããŠæ°ããåèªãæ¿å ¥ããŸãã
ãããã調æ»ã«ãããšãupdateSelectionã¡ãœããã1ååŒã³åºãã ãã§ã¯äžååã§ãã åèªã¯çœ®æãããŸããããsetComposingRegionãåŒã³åºãããªããããã«ãŒãœã«ã§çŸåšã®äœçœ®ã«è¿œå ãããŸãã
解決çãèŠã€ããã«ã¯ãEditTextãæäœãããšãã«åŒã³åºãããInputMethodManagerã¡ãœããã®ã·ãŒã±ã³ã¹ã確èªããå¿ èŠããããŸããããã¯æ¬¡ã®ããã«ãªããŸãã
inputMethodManager.viewClicked(view); inputMethodManager.updateSelection(view, cursorPosition, cursorPosition, cursorPosition, cursorPosition); // -1 composing region . inputMethodManager.updateSelection(view, cursorPosition, cursorPosition, -1, -1);
ããã§ãã³ã³ããŒãã³ããã¯ãªãã¯ããåŠçã«æå®ãããè¡ãè¿œå ãããšãããŒããŒããsetComposingRegionã®åŒã³åºããéå§ããããã¹ããæ£ãã眮ãæããããŸãã
ã³ãŒãäŸ
public class CustomView extends View { @NonNull private Editable mEditable; @NonNull private final InputMethodManager mImm; @NonNull private final MyTextWatcher mMyTextWatcher = new MyTextWatcher(); /** * , . > 0 - . */ private int mBatch; public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); // editable. mEditable = Editable.Factory.getInstance().newEditable(""); Selection.setSelection(mEditable, 0); // setFocusableInTouchMode(true); // setOnClickListener(v -> mImm.showSoftInput(v, 0)); // Editable mEditable.setSpan(mMyTextWatcher, 0, mEditable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); } @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { outAttrs.inputType = InputType.TYPE_CLASS_TEXT; outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE; outAttrs.initialSelEnd = outAttrs.initialSelStart = 0; // . return new BaseInputConnection(this, true) { @Override public Editable getEditable() { return mEditable; } @Override public boolean endBatchEdit() { mBatch++; return super.endBatchEdit(); } @Override public boolean beginBatchEdit() { mBatch--; return super.beginBatchEdit(); } }; } @Override public boolean onCheckIsTextEditor() { return true; } /** * . */ public void setText(@NonNull String newText) { mEditable = Editable.Factory.getInstance().newEditable(newText); mImm.restartInput(this); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP && mBatch == 0) { int cursorPosition = 0; // ( ) // notify keyboard that cursor position has changed. mImm.viewClicked(this); mImm.updateSelection(this, cursorPosition, cursorPosition, cursorPosition, cursorPosition); mImm.updateSelection(this, cursorPosition, cursorPosition, -1, -1); } return super.onTouchEvent(event); } private class MyTextWatcher implements TextWatcher { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { Log.d("CustomView", "Current text: " + mEditable); } @Override public void afterTextChanged(Editable editable) {} } }
ãŸãšã
EditTextããç¶æ¿ãããªãç¬èªã®ãšãã£ã¿ãŒã³ã³ããŒãã³ããäœæããããšã¯ãããªããŸããªã¿ã¹ã¯ã§ãã ããããããã«ééããå Žåã¯ãããŒããŒãã®ãµããŒãã«å¯ŸåŠããå¿ èŠããããŸãã æ¢ã«èšäºã§è¿°ã¹ãããã«ãæãç°¡åãªæ¹æ³ã¯SDKã«ããæ¢è£œã®å®è£ ã䜿çšããããšã§ãã ããããäœããã®çç±ã§é©åããªãå Žåã¯ããŸãèšäºã«èšèŒãããŠããæ¹æ³ã«äŸåãã䟡å€ããããŸã-ãããåºæ¬ã§ãã ããã«ãããã¥ã¡ã³ãããã詳现ã«èª¿ã¹ãããšãã§ããŸãã ãããŠæãå¹æçãªæ¹æ³ã¯ãTextViewã®ãœãŒã¹ã³ãŒãã調ã¹ãããšã§ãã