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

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

futabooo
March 09, 2017

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

futabooo

March 09, 2017
Tweet

More Decks by futabooo

Other Decks in Programming

Transcript

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

    View Slide

  2. 2
    About me
    - Lead Engineer at eureka, Inc.
    - Java, Kotlin, Golang, TypeScript, AngularJS
    - FantasyEarth Zero, s.CRY.ed
    futabooo
    futabooo
    futabooo (ס׋ע٦)

    View Slide

  3. 3
    About eureka
    https://eure.jp/

    View Slide

  4. 4
    About eureka

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  10. ،فٔ杝荈窩俑㶵㼪Ⰵ⵸
    10

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  15. ‣ ➬圫׾寸׭׷
    ˖ ➭爡،فٔד杝荈窩俑㶵ָ㹋鄲ׁ׸גְ׷׮
    ך׾灇瑔ׅ׷
    ˖ 堣腉׾峤ְ⳿ׅ
    ˖ ؙؔٔذ؍ך然钠
    ‣ Ꟛ涪ׅ׷
    ˖ ➬圫寸׭ד峤ְ⳿׃׋堣腉ך㹋鄲
    15
    Couplesಠࣗֆจࣈಋೖ·ͰͷྲྀΕ

    View Slide

  16. ➭爡،فٔך灇瑔
    16

    View Slide

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

    View Slide

  18. ‣ ػೳͷચ͍ग़݁͠Ռ
    • ֆจࣈΛදࣔͰ͖Δ
    • ֆจࣈͷίϐʔ&ϖʔετ͕Ͱ͖Δ
    • ΞϓϦ֎ʹϖʔετ͢Δͱ୅ସςΩετͰ
    දࣔ͞ΕΔ
    • ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ
    18
    ଞࣾΞϓϦͷݚڀ

    View Slide

  19. ַֿֿ׵Ꟛ涪ך鑧דׅ
    19

    View Slide

  20. 窩俑㶵׾邌爙ׅ׷
    20

    View Slide

  21. ‣ Ⳣ椚ך崧׸
    ˖ 邌爙ׅ׷俑㶵⴨ך⚥ַ׵窩俑㶵ח㼎䘔ׅ׷鿇ⴓ׾
    陎ⴽׅ׷
    ˖ 邌爙ׅ׷俑㶵⴨ךוֿחו׿ז窩俑㶵׾邌爙ׅ׷
    ַ׾⥂䭯ׅ׷ٔأز׾⡲䧭ׅ׷
    ˖ 邌爙ׅ׷俑㶵⴨׾4QBOOBCMF4USJOHח׃ծٔأز
    ׾⯋ח㼎䘔ׅ׷鿇ⴓ׾窩俑㶵ה׃ג䲽歗ׅ׷
    21
    ֆจࣈΛදࣔ͢Δ

    View Slide

  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()
    ύʔαʔ

    View Slide

  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()
    ύʔαʔ

    View Slide

  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型
    ύʔαʔ

    View Slide

  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型
    ύʔαʔ

    View Slide

  26. 26
    ֆจࣈΛදࣔ͢Δ
    // 表示したい文字列
    String message =
    "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";


    // どこにどの絵文字を表示するかを保持したリストを取得する

    List 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);
    ‣ ॲཧͷྲྀΕ

    View Slide

  27. 27
    ֆจࣈΛදࣔ͢Δ
    // 表示したい文字列
    String message =
    "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";


    // どこにどの絵文字を表示するかを保持したリストを取得する

    List 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);
    ‣ ॲཧͷྲྀΕ

    View Slide

  28. 28
    ֆจࣈΛදࣔ͢Δ
    // 表示したい文字列
    String message =
    "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";


    // どこにどの絵文字を表示するかを保持したリストを取得する

    List 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);
    ‣ ॲཧͷྲྀΕ

    View Slide

  29. 29
    ֆจࣈΛදࣔ͢Δ
    // 表示したい文字列
    String message =
    "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";


    // どこにどの絵文字を表示するかを保持したリストを取得する

    List 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);
    ‣ ॲཧͷྲྀΕ

    View Slide

  30. 30
    ֆจࣈΛදࣔ͢Δ
    // 表示したい文字列
    String message =
    "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";


    // どこにどの絵文字を表示するかを保持したリストを取得する

    List 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);
    ‣ ॲཧͷྲྀΕ

    View Slide

  31. 31
    ֆจࣈΛදࣔ͢Δ
    // 表示したい文字列
    String message =
    "こんにちは{{sticon(1,10)}}今日はいい天気ですね!{{sticon(2,20)}}";


    // どこにどの絵文字を表示するかを保持したリストを取得する

    List 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);
    ‣ ॲཧͷྲྀΕ

    View Slide

  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();

    data.put("three", "five");

    System.out.println(tmpl.execute(data));

    //result: "One, two, five. Three sir!"

    View Slide

  33. 33
    ֆจࣈΛදࣔ͢Δ
    String text = "One, two, {{three}}. Three sir!";

    Template tmpl = Mustache.compiler().compile(text);

    Map<> data = new HashMap();

    data.put("three", "five");

    System.out.println(tmpl.execute(data));

    //result: "One, two, five. Three sir!"
    ‣ {{ mustache }}
    • Logic-less templates
    • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ
    • Java࣮૷ samskivert/jmustache

    View Slide

  34. 34
    ֆจࣈΛදࣔ͢Δ
    String text = "One, two, {{three}}. Three sir!";

    Template tmpl = Mustache.compiler().compile(text);

    Map<> data = new HashMap();

    data.put("three", "five");

    System.out.println(tmpl.execute(data));

    //result: "One, two, five. Three sir!"
    ‣ {{ mustache }}
    • Logic-less templates
    • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ
    • Java࣮૷ samskivert/jmustache

    View Slide

  35. 35
    ֆจࣈΛදࣔ͢Δ
    String text = "One, two, {{three}}. Three sir!";

    Template tmpl = Mustache.compiler().compile(text);

    Map<> data = new HashMap();

    data.put("three", "five");

    System.out.println(tmpl.execute(data));

    //result: "One, two, five. Three sir!"
    ‣ {{ mustache }}
    • Logic-less templates
    • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ
    • Java࣮૷ samskivert/jmustache

    View Slide

  36. 36
    ֆจࣈΛදࣔ͢Δ
    String text = "One, two, {{three}}. Three sir!";

    Template tmpl = Mustache.compiler().compile(text);

    Map<> data = new HashMap();

    data.put("three", "five");

    System.out.println(tmpl.execute(data));

    //result: "One, two, five. Three sir!"
    ‣ {{ mustache }}
    • Logic-less templates
    • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ
    • Java࣮૷ samskivert/jmustache

    View Slide

  37. 37
    ֆจࣈΛදࣔ͢Δ
    String text = "One, two, {{three}}. Three sir!";

    Template tmpl = Mustache.compiler().compile(text);

    Map<> data = new HashMap();

    data.put("three", "five");

    System.out.println(tmpl.execute(data));

    //result: "One, two, five. Three sir!"
    ‣ {{ mustache }}
    • Logic-less templates
    • ୯७ͳஔ͖׵͑Λߦ͏ςϯϓϨʔτ
    • Java࣮૷ samskivert/jmustache

    View Slide

  38. 38
    ֆจࣈΛදࣔ͢Δ
    ‣ samskivert/jmustache
    ˖ 俑㶵UP俑㶵ך縧ֹ䳔ִז׵ֿה駈׶׷
    ˖ 窩俑㶵חׅ׷חכ穠㽷㹋鄲ָ䗳銲
    ˖ ٓ؎ـٓٔכ⢪׻׆חծػ٦؟׾荈⵸ד㹋鄲

    View Slide

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

    View Slide

  40. 40
    ֆจࣈΛදࣔ͢Δ
    ‣ {{sticon(1,10)}}
    • sticon͸ֆจࣈͷ͜ͱ
    • sticon(άϧʔϓIDɺID)ɺID͸શͯͷsticonͰҰҙ
    • શͯͷsticonͰҰҙͳID͸ελϯϓͱͯ͠ૹΔ
    ࣌ʹ׆༂

    View Slide

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

    Pattern IDS = Pattern.compile("(\\d+),(\\d+)");
    List getSticonSpanTokens(String rawText) {
    ArrayList 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);
    }
    }
    }
    ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ

    View Slide

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

    Pattern IDS = Pattern.compile("(\\d+),(\\d+)");
    List getSticonSpanTokens(String rawText) {
    ArrayList 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);
    }
    }
    }
    ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ

    View Slide

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

    Pattern IDS = Pattern.compile("(\\d+),(\\d+)");
    List getSticonSpanTokens(String rawText) {
    ArrayList 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);
    }
    }
    }
    ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ

    View Slide

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

    Pattern IDS = Pattern.compile("(\\d+),(\\d+)");
    List getSticonSpanTokens(String rawText) {
    ArrayList 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);
    }
    }
    }
    ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ

    View Slide

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

    Pattern IDS = Pattern.compile("(\\d+),(\\d+)");
    List getSticonSpanTokens(String rawText) {
    ArrayList 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);
    }
    }
    }
    ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ

    View Slide

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

    Pattern IDS = Pattern.compile("(\\d+),(\\d+)");
    List getSticonSpanTokens(String rawText) {
    ArrayList 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);
    }
    }
    }
    ‣ Ͳ͜ʹͲͷֆจࣈΛදࣔ͢Δ͔อ࣋ͨ͠Ϧετͷऔಘ

    View Slide

  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

    View Slide

  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;
    }

    View Slide

  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;
    }

    View Slide

  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に置換して描画する

    }
    }

    View Slide

  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
    • ֆจࣈ৘ใΛอ࣋͢ΔΫϥε

    View Slide

  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に置換して描画する

    }
    }

    View Slide

  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に置換して描画する

    }
    }

    View Slide

  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に置換して描画する

    }
    }

    View Slide

  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
    • ֆจࣈ৘ใΛอ࣋͢ΔΫϥε

    View Slide

  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に置換して描画する

    }
    }

    View Slide

  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()
    ύʔαʔ
    ‣ ͓͞Β͍

    View Slide

  58. 窩俑㶵׾
    ؝ؾ٦ل٦أزדֹ׷
    58

    View Slide

  59. ‣ ॲཧͷྲྀΕ
    • ίϐʔ͞ΕͨΒԼهจࣈྻΛΞϓϦ಺Ͱอ࣋͢Δ
    • ੜςΩετ ʮ͜Μʹͪ͸{{sticon(1,10)}}ʯ
    • ୅ସςΩετ ʮ͜Μʹͪ͸(bo)ʯ
    • ୅ସςΩετΛΫϦοϓϘʔυʹอଘ͢Δ
    • Couples֎Ͱͷϖʔετ͸୅ସςΩετදࣔ
    • ίϐʔ࣌ͷจࣈྻͱൺ্ֱͨ͠Ͱϖʔετ͢Δ
    59
    ֆจࣈΛίϐʔ&ϖʔετͰ͖Δ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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()) {
    // 絵文字表示処理
    }
    }

    View Slide

  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()) {
    // 絵文字表示処理
    }
    }

    View Slide

  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()) {
    // 絵文字表示処理
    }
    }

    View Slide

  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()) {
    // 絵文字表示処理
    }
    }

    View Slide

  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()) {
    // 絵文字表示処理
    }
    }

    View Slide

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

    View Slide

  70. 窩俑㶵⦐׌ֽד鷏׷ה
    أةٝفחז׷
    70

    View Slide

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

    View Slide

  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;

    }

    View Slide

  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;

    }

    View Slide

  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;

    }

    View Slide

  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;

    }

    View Slide

  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;

    }

    View Slide

  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 {
    // テキストメッセージ&絵文字として送信
    }

    View Slide

  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 {
    // テキストメッセージ&絵文字として送信
    }

    View Slide

  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 {
    // テキストメッセージ&絵文字として送信
    }

    View Slide

  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 {
    // テキストメッセージ&絵文字として送信
    }

    View Slide

  81. ‣ ͓͞Β͍
    81
    ֆจࣈ1ݸ͚ͩͰૹΔͱελϯϓʹͳΔ

    View Slide

  82. عو׏׋הֿ׹
    82

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  92. תה׭
    92

    View Slide

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

    View Slide

  94. Thank you
    Credit: NASA Earth Observatory/NOAA NGDC

    View Slide