Upgrade to Pro — share decks privately, control downloads, hide ads and more …

トークアプリで絵文字を実装した話

97370d6641bedd9849c3974c65935c0d?s=47 futabooo
March 09, 2017

 トークアプリで絵文字を実装した話

97370d6641bedd9849c3974c65935c0d?s=128

futabooo

March 09, 2017
Tweet

Transcript

  1. ز٦ؙ،فٔד窩俑㶵׾ 㹋鄲׃׋鑧 DroidKaigi 2017 @futabooo

  2. 2 About me - Lead Engineer at eureka, Inc. -

    Java, Kotlin, Golang, TypeScript, AngularJS - FantasyEarth Zero, s.CRY.ed futabooo futabooo futabooo (ס׋ע٦)
  3. 3 About eureka https://eure.jp/

  4. 4 About eureka

  5. 5 About eureka • Web • Golang, Gin • TypeScript,

    AngularJS • Android • Java, Kotlin • Dagger2, Orma, OkHttp3, Retrofit2, RxKotlin, Picasso, ButterKnife, DataBinding • iOS • Objective-C, Swift • CoreStore, Alamofire, Moya RxSwift, AsyncDisplayKit • Web • PHP, Codeigniter • Android • Java • ActiveAndroid, Volley, OkHttp3, Retrofit2, Socket.IO, RxJava, Glide • iOS • Swift, Objective-C • CoreStore, AFNetworking, SwiftyJSON, SDWebImage, RxSwift, Cartography
  6. ס׋׶ך䙼ְ⳿׾知⽃חⰟ剣 ،ٕغيծ鎸䙀傈ծأ؛آُ٦ٕ׾מהאחկ 06 About Couples ،ٕغي ٖؕٝت٦ 2" ز٦ؙ

  7. ס׋׶ך䙼ְ⳿׾知⽃חⰟ剣 ،ٕغيծ鎸䙀傈ծأ؛آُ٦ٕ׾מהאחկ 07 About Couples ،ٕغي ٖؕٝت٦ 2" ز٦ؙ

  8. 08 About Couples ز٦ؙ ‣ ذؗأزًحإ٦آ ‣ 窩俑㶵 ‣ ن؎أًحإ٦آ

    ‣ 歗⫷ ‣ ⹛歗 ‣ أةٝف ‣ ⡘縧䞔㜠 ‣ 5IJOLJOHPG:PV
  9. 09 About Couples ز٦ؙ ‣ ذؗأزًحإ٦آ ‣ 窩俑㶵 ‣ ن؎أًحإ٦آ

    ‣ 歗⫷ ‣ ⹛歗 ‣ أةٝف ‣ ⡘縧䞔㜠 ‣ 5IJOLJOHPG:PV
  10. ،فٔ杝荈窩俑㶵㼪Ⰵ⵸ 10

  11. 11 Ӣ$PVQMFTפך׀䠐鋅٥׀䠬䟝 歗⫷ך鸐׶窩俑㶵ָ邌爙ׁ׸תׇ׿ 猘ָ鷏׏׋׮ךכ邌爙ׁ׸׷׫׋ְדׅ

  12. Ӣ$PVQMFTפך׀䠐鋅٥׀䠬䟝 歗⫷ך鸐׶窩俑㶵ָ邌爙ׁ׸תׇ׿ 猘ָ鷏׏׋׮ךכ邌爙ׁ׸׷׫׋ְדׅ 12 畭劣װٍؗٔ،ך麩ְח״׏ג 姻׃ְ窩俑㶵ך邌爙ָדֹזְ

  13. 杝荈窩俑㶵ְ׸״ֲ 13

  14. $PVQMFT杝荈窩俑㶵 㼪Ⰵתדך崧׸ 14

  15. ‣ ➬圫׾寸׭׷ ˖ ➭爡،فٔד杝荈窩俑㶵ָ㹋鄲ׁ׸גְ׷׮ ך׾灇瑔ׅ׷ ˖ 堣腉׾峤ְ⳿ׅ ˖ ؙؔٔذ؍ך然钠 ‣

    Ꟛ涪ׅ׷ ˖ ➬圫寸׭ד峤ְ⳿׃׋堣腉ך㹋鄲 15 Couplesಠࣗֆจࣈಋೖ·ͰͷྲྀΕ
  16. ➭爡،فٔך灇瑔 16

  17. ‣ ➭爡،فٔד杝荈窩俑㶵ך֮׷،فٔ׾מ׋ׅ׵⢪ֲ ˖ -*/&ծ'BDFCPPL.FTTFOHFSծFUD ˖ غؚ׾鋅אֽ׷ּ׵ְך⹲ְד葿ղװ׷ 17 ଞࣾΞϓϦͷݚڀ

  18. ‣ ػೳͷચ͍ग़݁͠Ռ • ֆจࣈΛදࣔͰ͖Δ • ֆจࣈͷίϐʔ&ϖʔετ͕Ͱ͖Δ • ΞϓϦ֎ʹϖʔετ͢Δͱ୅ସςΩετͰ දࣔ͞ΕΔ •

    ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ 18 ଞࣾΞϓϦͷݚڀ
  19. ַֿֿ׵Ꟛ涪ך鑧דׅ 19

  20. 窩俑㶵׾邌爙ׅ׷ 20

  21. ‣ Ⳣ椚ך崧׸ ˖ 邌爙ׅ׷俑㶵⴨ך⚥ַ׵窩俑㶵ח㼎䘔ׅ׷鿇ⴓ׾ 陎ⴽׅ׷ ˖ 邌爙ׅ׷俑㶵⴨ךוֿחו׿ז窩俑㶵׾邌爙ׅ׷ ַ׾⥂䭯ׅ׷ٔأز׾⡲䧭ׅ׷ ˖ 邌爙ׅ׷俑㶵⴨׾4QBOOBCMF4USJOHח׃ծٔأز

    ׾⯋ח㼎䘔ׅ׷鿇ⴓ׾窩俑㶵ה׃ג䲽歗ׅ׷ 21 ֆจࣈΛදࣔ͢Δ
  22. ‣ Ⳣ椚ך崧׸ 22 ֆจࣈΛදࣔ͢Δ こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}} TalkMessageToken characterStyle : SticonSpan beginIndex

    : int endIndex : int TalkMessageToken characterStyle : SticonSpan beginIndex : int endIndex : int こんにちは 今日はいい天気ですね! SpannableString型 String型 SticonSpan sticon : Drawable altText : String DynamicDrawableSpan draw() ύʔαʔ
  23. ‣ ॲཧͷྲྀΕ 23 ֆจࣈΛදࣔ͢Δ こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}} TalkMessageToken characterStyle : SticonSpan beginIndex

    : int endIndex : int TalkMessageToken characterStyle : SticonSpan beginIndex : int endIndex : int こんにちは 今日はいい天気ですね! SpannableString型 String型 SticonSpan sticon : Drawable altText : String DynamicDrawableSpan draw() ύʔαʔ
  24. ‣ ॲཧͷྲྀΕ 24 ֆจࣈΛදࣔ͢Δ TalkMessageToken characterStyle : SticonSpan beginIndex :

    int endIndex : int TalkMessageToken characterStyle : SticonSpan beginIndex : int endIndex : int SticonSpan sticon : Drawable altText : String DynamicDrawableSpan draw() こんにちは 今日はいい天気ですね! SpannableString型 こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}} String型 ύʔαʔ
  25. ‣ ॲཧͷྲྀΕ 25 ֆจࣈΛදࣔ͢Δ TalkMessageToken characterStyle : SticonSpan beginIndex :

    int endIndex : int TalkMessageToken characterStyle : SticonSpan beginIndex : int endIndex : int SticonSpan sticon : Drawable altText : String DynamicDrawableSpan draw() こんにちは 今日はいい天気ですね! SpannableString型 こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}} String型 ύʔαʔ
  26. 26 ֆจࣈΛදࣔ͢Δ // 表示したい文字列 String message = "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";
 
 //

    どこにどの絵文字を表示するかを保持したリストを取得する
 List<TalkMessageToken> tokenList = TalkMessageHelper.getSticonSpanTokens(message); // リストを元に文字列に絵文字を対応させて描画する SpannableString spanedMessage = new SpannableString(message);
 for (TalkMessageToken t : tokenList) {
 spanedMessage .setSpan(t.characterStyle, t.beginIndex, t.endIndex, t.flags);
 }
 talkView.setText(spanedMessage); ‣ ॲཧͷྲྀΕ
  27. 27 ֆจࣈΛදࣔ͢Δ // 表示したい文字列 String message = "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";
 
 //

    どこにどの絵文字を表示するかを保持したリストを取得する
 List<TalkMessageToken> tokenList = TalkMessageHelper.getSticonSpanTokens(message); // リストを元に文字列に絵文字を対応させて描画する SpannableString spanedMessage = new SpannableString(message);
 for (TalkMessageToken t : tokenList) {
 spanedMessage .setSpan(t.characterStyle, t.beginIndex, t.endIndex, t.flags);
 }
 talkView.setText(spanedMessage); ‣ ॲཧͷྲྀΕ
  28. 28 ֆจࣈΛදࣔ͢Δ // 表示したい文字列 String message = "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";
 
 //

    どこにどの絵文字を表示するかを保持したリストを取得する
 List<TalkMessageToken> tokenList = TalkMessageHelper.getSticonSpanTokens(message); // リストを元に文字列に絵文字を対応させて描画する SpannableString spanedMessage = new SpannableString(message);
 for (TalkMessageToken t : tokenList) {
 spanedMessage .setSpan(t.characterStyle, t.beginIndex, t.endIndex, t.flags);
 }
 talkView.setText(spanedMessage); ‣ ॲཧͷྲྀΕ
  29. 29 ֆจࣈΛදࣔ͢Δ // 表示したい文字列 String message = "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";
 
 //

    どこにどの絵文字を表示するかを保持したリストを取得する
 List<TalkMessageToken> tokenList = TalkMessageHelper.getSticonSpanTokens(message); // リストを元に文字列に絵文字を対応させて描画する SpannableString spanedMessage = new SpannableString(message);
 for (TalkMessageToken t : tokenList) {
 spanedMessage .setSpan(t.characterStyle, t.beginIndex, t.endIndex, t.flags);
 }
 talkView.setText(spanedMessage); ‣ ॲཧͷྲྀΕ
  30. 30 ֆจࣈΛදࣔ͢Δ // 表示したい文字列 String message = "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";
 
 //

    どこにどの絵文字を表示するかを保持したリストを取得する
 List<TalkMessageToken> tokenList = TalkMessageHelper.getSticonSpanTokens(message); // リストを元に文字列に絵文字を対応させて描画する SpannableString spanedMessage = new SpannableString(message);
 for (TalkMessageToken t : tokenList) {
 spanedMessage .setSpan(t.characterStyle, t.beginIndex, t.endIndex, t.flags);
 }
 talkView.setText(spanedMessage); ‣ ॲཧͷྲྀΕ
  31. 31 ֆจࣈΛදࣔ͢Δ // 表示したい文字列 String message = "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";
 
 //

    どこにどの絵文字を表示するかを保持したリストを取得する
 List<TalkMessageToken> tokenList = TalkMessageHelper.getSticonSpanTokens(message); // リストを元に文字列に絵文字を対応させて描画する SpannableString spanedMessage = new SpannableString(message);
 for (TalkMessageToken t : tokenList) {
 spanedMessage .setSpan(t.characterStyle, t.beginIndex, t.endIndex, t.flags);
 }
 talkView.setText(spanedMessage); ‣ ॲཧͷྲྀΕ
  32. ‣ {{ mustache }} • Logic-less templates • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ •

    Java࣮૷ samskivert/jmustache 32 ֆจࣈΛදࣔ͢Δ String text = "One, two, {{three}}. Three sir!";
 Template tmpl = Mustache.compiler().compile(text);
 Map<> data = new HashMap<String, String>();
 data.put("three", "five");
 System.out.println(tmpl.execute(data));
 //result: "One, two, five. Three sir!"
  33. 33 ֆจࣈΛදࣔ͢Δ String text = "One, two, {{three}}. Three sir!";


    Template tmpl = Mustache.compiler().compile(text);
 Map<> data = new HashMap<String, String>();
 data.put("three", "five");
 System.out.println(tmpl.execute(data));
 //result: "One, two, five. Three sir!" ‣ {{ mustache }} • Logic-less templates • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ • Java࣮૷ samskivert/jmustache
  34. 34 ֆจࣈΛදࣔ͢Δ String text = "One, two, {{three}}. Three sir!";


    Template tmpl = Mustache.compiler().compile(text);
 Map<> data = new HashMap<String, String>();
 data.put("three", "five");
 System.out.println(tmpl.execute(data));
 //result: "One, two, five. Three sir!" ‣ {{ mustache }} • Logic-less templates • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ • Java࣮૷ samskivert/jmustache
  35. 35 ֆจࣈΛදࣔ͢Δ String text = "One, two, {{three}}. Three sir!";


    Template tmpl = Mustache.compiler().compile(text);
 Map<> data = new HashMap<String, String>();
 data.put("three", "five");
 System.out.println(tmpl.execute(data));
 //result: "One, two, five. Three sir!" ‣ {{ mustache }} • Logic-less templates • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ • Java࣮૷ samskivert/jmustache
  36. 36 ֆจࣈΛදࣔ͢Δ String text = "One, two, {{three}}. Three sir!";


    Template tmpl = Mustache.compiler().compile(text);
 Map<> data = new HashMap<String, String>();
 data.put("three", "five");
 System.out.println(tmpl.execute(data));
 //result: "One, two, five. Three sir!" ‣ {{ mustache }} • Logic-less templates • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ • Java࣮૷ samskivert/jmustache
  37. 37 ֆจࣈΛදࣔ͢Δ String text = "One, two, {{three}}. Three sir!";


    Template tmpl = Mustache.compiler().compile(text);
 Map<> data = new HashMap<String, String>();
 data.put("three", "five");
 System.out.println(tmpl.execute(data));
 //result: "One, two, five. Three sir!" ‣ {{ mustache }} • Logic-less templates • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ • Java࣮૷ samskivert/jmustache
  38. 38 ֆจࣈΛදࣔ͢Δ ‣ samskivert/jmustache ˖ 俑㶵UP俑㶵ך縧ֹ䳔ִז׵ֿה駈׶׷ ˖ 窩俑㶵חׅ׷חכ穠㽷㹋鄲ָ䗳銲 ˖ ٓ؎ـٓٔכ⢪׻׆חծػ٦؟׾荈⵸ד㹋鄲

  39. 39 ֆจࣈΛදࣔ͢Δ ‣ ࣗલύʔαʔ • mustacheΛ࢖͍ͳ͕Βਖ਼نදݱͰΰϦΰϦ΍Δ • MatcherͱPatternΛ࢖͏ • {{sticon(1,10)}}

    → ରԠ͢Δֆจࣈ Λදࣔ͢ΔͨΊͷSpanΛ࡞੒͢Δ
  40. 40 ֆจࣈΛදࣔ͢Δ ‣ {{sticon(1,10)}} • sticon͸ֆจࣈͷ͜ͱ • sticon(άϧʔϓIDɺID)ɺID͸શͯͷsticonͰҰҙ • શͯͷsticonͰҰҙͳID͸ελϯϓͱͯ͠ૹΔ

    ࣌ʹ׆༂
  41. 41 ֆจࣈΛදࣔ͢Δ // 正規表現のパターンを作成する Pattern STICON = Pattern.compile("\\{\\{sticon\\(.+?\\)\\}\\}");
 Pattern IDS

    = Pattern.compile("(\\d+),(\\d+)"); List<TalkMessageToken> getSticonSpanTokens(String rawText) { ArrayList<TalkMessageToken> tokens = new ArrayList<>(); // Matcherを用いてパターンにマッチした部分へ処理を行う
 Matcher t = STICON.matcher(rawText);
 Matcher ids = IDS.matcher(""); while (t.find()) {// {{sticon(1,10)}}と{{sticon(2,20)}} matcherIds.reset(matcherTemplate.group());
 if (ids.find()) {// (1,10)と(2,20) TalkMessageToken token = new TalkMessageToken(sticonSpan, t.start(), t.end());
 tokens.add(token); } } } ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ
  42. 42 ֆจࣈΛදࣔ͢Δ // 正規表現のパターンを作成する Pattern STICON = Pattern.compile("\\{\\{sticon\\(.+?\\)\\}\\}");
 Pattern IDS

    = Pattern.compile("(\\d+),(\\d+)"); List<TalkMessageToken> getSticonSpanTokens(String rawText) { ArrayList<TalkMessageToken> tokens = new ArrayList<>(); // Matcherを用いてパターンにマッチした部分へ処理を行う
 Matcher t = STICON.matcher(rawText);
 Matcher ids = IDS.matcher(""); while (t.find()) {// {{sticon(1,10)}}と{{sticon(2,20)}} matcherIds.reset(t.group());
 if (ids.find()) {// (1,10)と(2,20) TalkMessageToken token = new TalkMessageToken(sticonSpan, t.start(), t.end());
 tokens.add(token); } } } ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ
  43. 43 ֆจࣈΛදࣔ͢Δ // 正規表現のパターンを作成する Pattern STICON = Pattern.compile("\\{\\{sticon\\(.+?\\)\\}\\}");
 Pattern IDS

    = Pattern.compile("(\\d+),(\\d+)"); List<TalkMessageToken> getSticonSpanTokens(String rawText) { ArrayList<TalkMessageToken> tokens = new ArrayList<>(); // Matcherを用いてパターンにマッチした部分へ処理を行う
 Matcher t = STICON.matcher(rawText);
 Matcher ids = IDS.matcher(""); while (t.find()) {// {{sticon(1,10)}}と{{sticon(2,20)}} matcherIds.reset(t.group())
 if (ids.find()) {// (1,10)と(2,20) TalkMessageToken token = new TalkMessageToken(sticonSpan, t.start(), t.end());
 tokens.add(token); } } } ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ
  44. 44 ֆจࣈΛදࣔ͢Δ // 正規表現のパターンを作成する Pattern STICON = Pattern.compile("\\{\\{sticon\\(.+?\\)\\}\\}");
 Pattern IDS

    = Pattern.compile("(\\d+),(\\d+)"); List<TalkMessageToken> getSticonSpanTokens(String rawText) { ArrayList<TalkMessageToken> tokens = new ArrayList<>(); // Matcherを用いてパターンにマッチした部分へ処理を行う
 Matcher t = STICON.matcher(rawText);
 Matcher ids = IDS.matcher(""); while (t.find()) {// {{sticon(1,10)}}と{{sticon(2,20)}}
 matcherIds.reset(t.group()); if (ids.find()) {// (1,10)と(2,20) TalkMessageToken token = new TalkMessageToken(sticonSpan, t.start(), t.end());
 tokens.add(token); } } } ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ
  45. 45 ֆจࣈΛදࣔ͢Δ // 正規表現のパターンを作成する Pattern STICON = Pattern.compile("\\{\\{sticon\\(.+?\\)\\}\\}");
 Pattern IDS

    = Pattern.compile("(\\d+),(\\d+)"); List<TalkMessageToken> getSticonSpanTokens(String rawText) { ArrayList<TalkMessageToken> tokens = new ArrayList<>(); // Matcherを用いてパターンにマッチした部分へ処理を行う
 Matcher t = STICON.matcher(rawText);
 Matcher ids = IDS.matcher(""); while (t.find()) {// {{sticon(1,10)}}と{{sticon(2,20)}} matcherIds.reset(t.group());
 if (ids.find()) {// (1,10)と(2,20) TalkMessageToken token = new TalkMessageToken(sticonSpan, t.start(), t.end());
 tokens.add(token); } } } ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ
  46. 46 ֆจࣈΛදࣔ͢Δ // 正規表現のパターンを作成する Pattern STICON = Pattern.compile("\\{\\{sticon\\(.+?\\)\\}\\}");
 Pattern IDS

    = Pattern.compile("(\\d+),(\\d+)"); List<TalkMessageToken> getSticonSpanTokens(String rawText) { ArrayList<TalkMessageToken> tokens = new ArrayList<>(); // Matcherを用いてパターンにマッチした部分へ処理を行う
 Matcher t = STICON.matcher(rawText);
 Matcher ids = IDS.matcher(""); while (t.find()) {// {{sticon(1,10)}}と{{sticon(2,20)}} matcherIds.reset(t.group());
 if (ids.find()) {// (1,10)と(2,20) TalkMessageToken token = new TalkMessageToken(sticonSpan, t.start(), t.end());
 tokens.add(token); } } } ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ
  47. 47 ֆจࣈΛදࣔ͢Δ class TalkMessageToken {
 public CharacterStyle characterStyle;
 public int

    beginIndex;
 public int endIndex; } ‣ TalkMessageToken • Ͳ͜ʹͲΜͳελΠϧΛ౰ͯΔ͔อ࣋͢ΔΫϥε こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}} TalkMessageToken characterStyle = sticonSpan beginIndex = 5 endIndex = 20 TalkMessageToken characterStyle = sticonSpan beginIndex = 32 endIndex = 47
  48. 48 ֆจࣈΛදࣔ͢Δ ‣ TalkMessageToken • Ͳ͜ʹͲΜͳελΠϧΛ౰ͯΔ͔อ࣋͢ΔΫϥε こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}} TalkMessageToken characterStyle =

    sticonSpan beginIndex = 5 endIndex = 20 TalkMessageToken characterStyle = sticonSpan beginIndex = 32 endIndex = 47 class TalkMessageToken {
 public CharacterStyle characterStyle;
 public int beginIndex;
 public int endIndex; }
  49. 49 ֆจࣈΛදࣔ͢Δ ‣ TalkMessageToken • Ͳ͜ʹͲΜͳελΠϧΛ౰ͯΔ͔อ࣋͢ΔΫϥε こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}} TalkMessageToken characterStyle =

    sticonSpan beginIndex = 5 endIndex = 20 TalkMessageToken characterStyle = sticonSpan beginIndex = 32 endIndex = 47 class TalkMessageToken {
 public CharacterStyle characterStyle;
 public int beginIndex;
 public int endIndex; }
  50. 50 ֆจࣈΛදࣔ͢Δ ‣ SticonSpan • ֆจࣈ৘ใΛอ࣋͢ΔΫϥε class SticonSpan extends DynamicDrawableSpan

    { Drawable sticon;
 String altText;
 String rawText; int stickerId; 
 @Override
 public void draw(Canvas canvas, CharSequence text,
 int start, int end, float x,
 int top, int y, int bottom, Paint paint) { // 自身が適用されたstring部分をsticonに置換して描画する
 } }
  51. 51 ֆจࣈΛදࣔ͢Δ class SticonSpan extends DynamicDrawableSpan { Drawable sticon;
 String

    altText;
 String rawText; int stickerId; 
 @Override
 public void draw(Canvas canvas, CharSequence text,
 int start, int end, float x,
 int top, int y, int bottom, Paint paint) { // 自身が適用されたstring部分をsticonに置換して描画する
 } } ‣ SticonSpan • ֆจࣈ৘ใΛอ࣋͢ΔΫϥε
  52. 52 ֆจࣈΛදࣔ͢Δ ‣ SticonSpan • ֆจࣈ৘ใΛอ࣋͢ΔΫϥε class SticonSpan extends DynamicDrawableSpan

    { Drawable sticon;
 String altText;
 String rawText; int stickerId; 
 @Override
 public void draw(Canvas canvas, CharSequence text,
 int start, int end, float x,
 int top, int y, int bottom, Paint paint) { // 自身が適用されたstring部分をsticonに置換して描画する
 } }
  53. 53 ֆจࣈΛදࣔ͢Δ ‣ SticonSpan • ֆจࣈ৘ใΛอ࣋͢ΔΫϥε class SticonSpan extends DynamicDrawableSpan

    { Drawable sticon;
 String altText;
 String rawText; int stickerId; 
 @Override
 public void draw(Canvas canvas, CharSequence text,
 int start, int end, float x,
 int top, int y, int bottom, Paint paint) { // 自身が適用されたstring部分をsticonに置換して描画する
 } }
  54. 54 ֆจࣈΛදࣔ͢Δ ‣ SticonSpan • ֆจࣈ৘ใΛอ࣋͢ΔΫϥε class SticonSpan extends DynamicDrawableSpan

    { Drawable sticon;
 String altText;
 String rawText; int stickerId; 
 @Override
 public void draw(Canvas canvas, CharSequence text,
 int start, int end, float x,
 int top, int y, int bottom, Paint paint) { // 自身が適用されたstring部分をsticonに置換して描画する
 } }
  55. 55 ֆจࣈΛදࣔ͢Δ class SticonSpan extends DynamicDrawableSpan { Drawable sticon;
 String

    altText;
 String rawText; int stickerId; 
 @Override
 public void draw(Canvas canvas, CharSequence text,
 int start, int end, float x,
 int top, int y, int bottom, Paint paint) { // 自身が適用されたstring部分をsticonに置換して描画する
 } } ‣ SticonSpan • ֆจࣈ৘ใΛอ࣋͢ΔΫϥε
  56. 56 ֆจࣈΛදࣔ͢Δ ‣ SticonSpan • ֆจࣈ৘ใΛอ࣋͢ΔΫϥε class SticonSpan extends DynamicDrawableSpan

    { Drawable sticon;
 String altText;
 String rawText; int stickerId; 
 @Override
 public void draw(Canvas canvas, CharSequence text,
 int start, int end, float x,
 int top, int y, int bottom, Paint paint) { // 自身が適用されたstring部分をsticonに置換して描画する
 } }
  57. こんにちは 今日はいい天気ですね! 57 ֆจࣈΛදࣔ͢Δ こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}} TalkMessageToken characterStyle : SticonSpan beginIndex

    : int endIndex : int TalkMessageToken characterStyle : SticonSpan beginIndex : int endIndex : int SpannableString型 String型 SticonSpan sticon : Drawable altText : String DynamicDrawableSpan draw() ύʔαʔ ‣ ͓͞Β͍
  58. 窩俑㶵׾ ؝ؾ٦ل٦أزדֹ׷ 58

  59. ‣ ॲཧͷྲྀΕ • ίϐʔ͞ΕͨΒԼهจࣈྻΛΞϓϦ಺Ͱอ࣋͢Δ • ੜςΩετ ʮ͜Μʹͪ͸{{sticon(1,10)}}ʯ • ୅ସςΩετ ʮ͜Μʹͪ͸(bo)ʯ

    • ୅ସςΩετΛΫϦοϓϘʔυʹอଘ͢Δ • Couples֎Ͱͷϖʔετ͸୅ସςΩετදࣔ • ίϐʔ࣌ͷจࣈྻͱൺ্ֱͨ͠Ͱϖʔετ͢Δ 59 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ
  60. ‣ ॲཧͷྲྀΕ 60 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ SpannableString型 こんにちは 今日はいい天気ですね! Copy copiedRawText: String

    copiedAltText : String sticonCopied: boolean ΞϓϦ಺ ΫϦοϓϘʔυ copiedAltText : String Paste こんにちは 今日はいい天気ですね! こんにちは(bo)今日はいい天気ですね!(Sunny)
  61. ‣ ॲཧͷྲྀΕ 61 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ SpannableString型 こんにちは 今日はいい天気ですね! Copy copiedRawText: String

    copiedAltText : String sticonCopied: boolean ΞϓϦ಺ ΫϦοϓϘʔυ copiedAltText : String Paste こんにちは 今日はいい天気ですね! こんにちは(bo)今日はいい天気ですね!(Sunny)
  62. ‣ ॲཧͷྲྀΕ 62 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ SpannableString型 こんにちは 今日はいい天気ですね! Copy copiedRawText: String

    copiedAltText : String sticonCopied: boolean ΞϓϦ಺ ΫϦοϓϘʔυ copiedAltText : String Paste こんにちは 今日はいい天気ですね! こんにちは(bo)今日はいい天気ですね!(Sunny)
  63. ‣ ॲཧͷྲྀΕ 63 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ SpannableString型 こんにちは 今日はいい天気ですね! Copy copiedRawText: String

    copiedAltText : String sticonCopied: boolean ΞϓϦ಺ ΫϦοϓϘʔυ copiedAltText : String Paste こんにちは 今日はいい天気ですね! こんにちは(bo)今日はいい天気ですね!(Sunny)
  64. 64 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ ‣ ॲཧͷྲྀΕ // 文字列をアプリ内に保持する setCopiedText(message); // クリップボードに代替テキストを保存 altText

    = TalkMessageHelper.getAltText(message);
 String[] mimetype = {ClipDescription.MIMETYPE_TEXT_PLAIN};
 ClipData.Item item = new ClipData.Item(altText);
 ClipData cd = new ClipData(new ClipDescription("text",mimetype),item);
 ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
 cm.setPrimaryClip(cd); // コピー時の文字列と比較した上で貼り付け @Override public void afterTextChanged(Editable s) { if (isSticonPasted()) { // 絵文字表示処理 } }
  65. 65 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ ‣ ॲཧͷྲྀΕ // 文字列をアプリ内に保持する setCopiedText(message); // クリップボードに代替テキストを保存 altText

    = TalkMessageHelper.getAltText(message);
 String[] mimetype = {ClipDescription.MIMETYPE_TEXT_PLAIN};
 ClipData.Item item = new ClipData.Item(altText);
 ClipData cd = new ClipData(new ClipDescription("text",mimetype),item);
 ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
 cm.setPrimaryClip(cd); // コピー時の文字列と比較した上で貼り付け @Override public void afterTextChanged(Editable s) { if (isSticonPasted()) { // 絵文字表示処理 } }
  66. 66 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ ‣ ॲཧͷྲྀΕ // 文字列をアプリ内に保持する setCopiedText(message); // クリップボードに代替テキストを保存 altText

    = TalkMessageHelper.getAltText(message);
 String[] mimetype = {ClipDescription.MIMETYPE_TEXT_PLAIN};
 ClipData.Item item = new ClipData.Item(altText);
 ClipData cd = new ClipData(new ClipDescription("text",mimetype),item);
 ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
 cm.setPrimaryClip(cd); // コピー時の文字列と比較した上で貼り付け @Override public void afterTextChanged(Editable s) { if (isSticonPasted()) { // 絵文字表示処理 } }
  67. 67 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ ‣ ॲཧͷྲྀΕ // 文字列をアプリ内に保持する setCopiedText(message); // クリップボードに代替テキストを保存 altText

    = TalkMessageHelper.getAltText(message);
 String[] mimetype = {ClipDescription.MIMETYPE_TEXT_PLAIN};
 ClipData.Item item = new ClipData.Item(altText);
 ClipData cd = new ClipData(new ClipDescription("text",mimetype),item);
 ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
 cm.setPrimaryClip(cd); // コピー時の文字列と比較した上で貼り付け @Override public void afterTextChanged(Editable s) { if (isSticonPasted()) { // 絵文字表示処理 } }
  68. 68 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ ‣ ॲཧͷྲྀΕ // 文字列をアプリ内に保持する setCopiedText(message); // クリップボードに代替テキストを保存 altText

    = TalkMessageHelper.getAltText(message);
 String[] mimetype = {ClipDescription.MIMETYPE_TEXT_PLAIN};
 ClipData.Item item = new ClipData.Item(altText);
 ClipData cd = new ClipData(new ClipDescription("text",mimetype),item);
 ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
 cm.setPrimaryClip(cd); // コピー時の文字列と比較した上で貼り付け @Override public void afterTextChanged(Editable s) { if (isSticonPasted()) { // 絵文字表示処理 } }
  69. ‣ ͓͞Β͍ 69 ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ SpannableString型 こんにちは 今日はいい天気ですね! Copy copiedRawText: String

    copiedAltText : String sticonCopied: boolean ΞϓϦ಺ ΫϦοϓϘʔυ copiedAltText : String Paste こんにちは 今日はいい天気ですね! こんにちは(bo)今日はいい天気ですね!(Sunny)
  70. 窩俑㶵⦐׌ֽד鷏׷ה أةٝفחז׷ 70

  71. ‣ ॲཧͷྲྀΕ • ϝοηʔδૹ৴ͷλΠϛϯάͰֆจࣈ1ݸ͚͔ͩ Ͳ͏͔Λ൑ఆ͢Δ • ֆจࣈ1ݸ͚ͩͷ৔߹ɺελϯϓͱͯ͠ૹ৴͢Δ 71 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ

  72. ‣ ελϯϓͱͯ͠ૹΔ͔Ͳ͏͔൑ఆ͢Δ 72 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ public boolean isSendSticonAsSticker(){
 SticonSpan[] tokens =editText.getText().getSpans(

    0, editText.getText().length(), SticonSpan.class); if(tokens.length == 1){ // 絵文字を表す文字列が1個だけ入力されてる場合
 if(tokens[0].getTemplateString().equals(editText.getText())){
 return true;
 }
 } // 絵文字が1個だけじゃない場合
 return false;
 }
  73. ‣ ελϯϓͱͯ͠ૹΔ͔Ͳ͏͔൑ఆ͢Δ 73 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ public boolean isSendSticonAsSticker(){
 SticonSpan[] tokens =editText.getText().getSpans(

    0, editText.getText().length(), SticonSpan.class); if(tokens.length == 1){ // 絵文字を表す文字列が1個だけ入力されてる場合
 if(tokens[0].getTemplateString().equals(editText.getText())){
 return true;
 }
 } // 絵文字が1個だけじゃない場合
 return false;
 }
  74. ‣ ελϯϓͱͯ͠ૹΔ͔Ͳ͏͔൑ఆ͢Δ 74 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ public boolean isSendSticonAsSticker(){
 SticonSpan[] tokens =editText.getText().getSpans(

    0, editText.getText().length(), SticonSpan.class); if(tokens.length == 1){ // 絵文字を表す文字列が1個だけ入力されてる場合
 if(tokens[0].getTemplateString().equals(editText.getText())){
 return true;
 }
 } // 絵文字が1個だけじゃない場合
 return false;
 }
  75. ‣ ελϯϓͱͯ͠ૹΔ͔Ͳ͏͔൑ఆ͢Δ 75 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ public boolean isSendSticonAsSticker(){
 SticonSpan[] tokens =editText.getText().getSpans(

    0, editText.getText().length(), SticonSpan.class); if(tokens.length == 1){ // 絵文字を表す文字列が1個だけ入力されてる場合
 if(tokens[0].getTemplateString().equals(editText.getText())){
 return true;
 }
 } // 絵文字が1個だけじゃない場合
 return false;
 }
  76. ‣ ελϯϓͱͯ͠ૹΔ͔Ͳ͏͔൑ఆ͢Δ 76 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ public boolean isSendSticonAsSticker(){
 SticonSpan[] tokens =editText.getText().getSpans(

    0, editText.getText().length(), SticonSpan.class); if(tokens.length == 1){ // 絵文字を表す文字列が1個だけ入力されてる場合
 if(tokens[0].getTemplateString().equals(editText.getText())){
 return true;
 }
 } // 絵文字が1個だけじゃない場合
 return false;
 }
  77. ‣ ελϯϓΛૹΔ 77 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ if (isSendSticonAsSticker()) { Editable t =

    editText.getText() SticonSpan[] spans = t.getSpans(0, t.length(), SticonSpan.class);
 // スタンプを生成して送信 Sticker sticker = new Sticker(spans[0].getSticonId());
 sendStamp(sticker); } else { // テキストメッセージ&絵文字として送信 }
  78. ‣ ελϯϓΛૹΔ 78 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ if (isSendSticonAsSticker()) { Editable t =

    editText.getText() SticonSpan[] spans = t.getSpans(0, t.length(), SticonSpan.class);
 // スタンプを生成して送信 Sticker sticker = new Sticker(spans[0].getSticonId());
 sendStamp(sticker); } else { // テキストメッセージ&絵文字として送信 }
  79. ‣ ελϯϓΛૹΔ 79 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ if (isSendSticonAsSticker()) { Editable t =

    editText.getText() SticonSpan[] spans = t.getSpans(0, t.length(), SticonSpan.class);
 // スタンプを生成して送信 Sticker sticker = new Sticker(spans[0].getSticonId());
 sendStamp(sticker); } else { // テキストメッセージ&絵文字として送信 }
  80. ‣ ελϯϓΛૹΔ 80 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ if (isSendSticonAsSticker()) { Editable t =

    editText.getText() SticonSpan[] spans = t.getSpans(0, t.length(), SticonSpan.class);
 // スタンプを生成して送信 Sticker sticker = new Sticker(spans[0].getSticonId());
 sendStamp(sticker); } else { // テキストメッセージ&絵文字として送信 }
  81. ‣ ͓͞Β͍ 81 ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ

  82. عو׏׋הֿ׹ 82

  83. ‣ 㣐ꆀך窩俑㶵׾邌爙ׅ׷הأؙٗ٦ָؙٕؕאֻ ‣ 窩俑㶵ך؝ؾل׾ׅ׷ה俑㶵ָⴖ׸׷ 83 ϋϚͬͨͱ͜Ζ

  84. ‣ 㣐ꆀך窩俑㶵׾邌爙ׅ׷הأؙٗ٦ָؙٕؕאֻ ‣ 窩俑㶵ך؝ؾل׾ׅ׷ה俑㶵ָⴖ׸׷ 84 ϋϚͬͨͱ͜Ζ

  85. ‣ أؙٗ٦ٕךؙؕאֹכDBDIF㼪Ⰵד鍑寸 ˖ -SV$BDIF ˖ 俑㶵؟؎ؤחさ׻ׇג窩俑㶵ך؟؎ؤ׮㢌⻉ׅ ׷ךדծLFZח俑㶵؟؎ؤ׮Ⰵ׸׷ 85 େྔͷֆจࣈΛදࣔ͢ΔͱεΫϩʔϧ͕ΧΫͭ͘

  86. ‣ أؙٗ٦ٕךؙؕאֹכDBDIF㼪Ⰵד鍑寸 86 େྔͷֆจࣈΛදࣔ͢ΔͱεΫϩʔϧ͕ΧΫͭ͘ Before After

  87. ‣ 㣐ꆀך窩俑㶵׾邌爙ׅ׷הأؙٗ٦ָؙٕؕאֻ ‣ 窩俑㶵ך؝ؾل׾ׅ׷ה俑㶵ָⴖ׸׷ 87 ϋϚͬͨͱ͜Ζ

  88. ‣ ؝ؾلך眔㔲׾锃侭ׅ׷ٗآحؙ׾鷄⸇ׅ׷ 88 ֆจࣈͷίϐϖΛ͢Δͱจࣈ͕੾ΕΔ こんにちは 今日はいい天気ですね! Copy こんにちは{{sticon(1,10)}} ׉ךתת׌הNVTUBDIFך鷿⚥דⴖ׸׷ こんにちは{{sticon(1,10)}}

    ؝ؾلך眔㔲׾NVTUBDIFך穄畭ח⠼לׅ
  89. ‣ ؝ؾلך眔㔲׾锃侭ׅ׷ٗآحؙ׾鷄⸇ׅ׷ 89 ֆจࣈͷίϐϖΛ͢Δͱจࣈ͕੾ΕΔ こんにちは 今日はいい天気ですね! Copy こんにちは{{sticon(1,10)}} ׉ךתת׌הNVTUBDIFך鷿⚥דⴖ׸׷ こんにちは{{sticon(1,10)}}

    ؝ؾلך眔㔲׾NVTUBDIFך穄畭ח⠼לׅ
  90. ‣ ؝ؾلך眔㔲׾锃侭ׅ׷ٗآحؙ׾鷄⸇ׅ׷ 90 ֆจࣈͷίϐϖΛ͢Δͱจࣈ͕੾ΕΔ こんにちは 今日はいい天気ですね! Copy こんにちは{{sticon(1,10)}} ׉ךתת׌הNVTUBDIFך鷿⚥דⴖ׸׷ こんにちは{{sticon(1,10)}}

    ؝ؾلך眔㔲׾NVTUBDIFך穄畭ח⠼לׅ
  91. ‣ ؝ؾلך眔㔲׾锃侭ׅ׷ٗآحؙ׾鷄⸇ׅ׷ 91 ֆจࣈͷίϐϖΛ͢Δͱจࣈ͕੾ΕΔ こんにちは 今日はいい天気ですね! Copy こんにちは{{sticon(1,10)}} ׉ךתת׌הNVTUBDIFך鷿⚥דⴖ׸׷ こんにちは{{sticon(1,10)}}

    ؝ؾلך眔㔲׾NVTUBDIFך穄畭ח⠼לׅ
  92. תה׭ 92

  93. ‣ 㹋鄲ך倯岀ָⴓַ׵זְ儗כ⿫罋חדֹ׷،فٔ׾ 䱱׃ג⹛⡲׾锃ץ׷ ‣ 窩俑㶵ך邌爙חכ4QBOOBCMF4USJOHה䭁䓸׃׋ 4QBOؙٓأ׾⢪ֲ ‣ 邌爙♳窩俑㶵ח鋅ִ׷׌ֽדUFYUכ俑㶵⴨ָⰅ׏ג ְ׷ךדծ؝ؾلזו&EJU5FYUװ5FYU7JFXפךⳢ椚 כ岣䠐ׅ׷

    93 ·ͱΊ
  94. Thank you Credit: NASA Earth Observatory/NOAA NGDC