问题
I am trying to figure out how the emoji (emoticon) selections are implemented on the Facebook
app and the Google Hangouts
app. I looked into the SoftKeyboard
Demo app in the Android API Samples but the display of these emoji views does not look like a SoftKeyboard
. It looks and behaves more like a custom Dialog
view. Does anyone have an idea of how these are implemented?
Facebook App
Google Hangouts app
Also, is Unicode the best way to send emoticons or is there an alternative? I noticed that some Unicode
sequences like \\u1F601
don\'t render the corresponding emoticon and instead that sequence just shows up as 1
:
EditText messageInput = (EditText) findViewById(R.id.message_input);
messageInput.getText().append(\"\\u1F601\");
回答1:
I found a very useful Emoticon Keyboard. This keyboard is not using Unicode sequences but rather just local image assets. I am thinking that this type of keyboard can only be useful within this app and not with other apps or Operating Systems.
So instead I am replacing the ImageView
containing an asset with a TextView
containing a Unicode sequence.
After cross referencing Supported Unicode Sequences as well as the Visual Unicode Database I realized that \u1F601
was a 32 bit Unicode representation, and the 16bit representation can be set like :
EditText messageInput = (EditText) findViewById(R.id.message_input);
messageInput.getText().append("\ud83d\ude01");
回答2:
You can use this library based on Hieu Rocker's library: https://github.com/ankushsachdeva/emojicon
This is how it looks
回答3:
A viewgroup be visible or gone also can relize that,It doesn't neet the dialog. Every time initialize the emotion , I always user a key value like [happy]=R.drawable.happy. this is the text to emotion while content like [happy]
public SpannableString textToImage(String content,Context c){
SpannableString ss = new SpannableString(content);
int starts = 0;
int end = 0;
if(content.indexOf("[", starts) != -1 && content.indexOf("]", end) != -1){
starts = content.indexOf("[", starts);
end = content.indexOf("]", end);
SharedPreferences shared=c.getSharedPreferences("emotion",0);
int resource=shared.getInt(content,0);
try {
Drawable drawable =c.getResources().getDrawable(resource);
if (drawable != null) {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
ImageSpan span = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
ss.setSpan(span, starts,end + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} catch (Exception ex){
}
}
return ss;
}
回答4:
If you don't want to get into details of how to implement the Emoji-Keyboard functionality, you can try these libraries:
Rockerhieu / emojicon: implements the Emoji-Keyboard using fragments (you will need to handle the display of it using a DialogFragment. It doesn't have support for changing the layout and the default one is Hole Dark theme;
Android Emoji Keyboard: Based on Rockerhieu work I've built another lib that provides the emoji-keyboard as closer to what we've seen in apps such as WhatsApp or Telegram. You can handle the layout as a LinearLayout and, therefore, handle the interaction with the soft keyboard yourself (as described below) or choose to use Telegram Panel or WhatsApp Panel, both provided by the library, that does it for you.
PS1: Both libraries are Apache License
Part 01: Building the layout
Create a GridView for each Emoji-Page you want in your keyboard. For instance:
Bind the created views in Fragments:
public class FragmentEmojiNature extends FragmentEmoji { public static final String TAG = "FragmentEmojiNature"; private View mRootView; private Emoji[] mData; private boolean mUseSystemDefault = false; private static final String USE_SYSTEM_DEFAULT_KEY = "useSystemDefaults"; private static final String EMOJI_KEY = "emojic"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { this.mRootView = inflater.inflate(R.layout.frag_emoji_nature, container, false); return this.mRootView; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { GridView gridView = (GridView) view.findViewById(R.id.Emoji_GridView); Bundle bundle = getArguments(); if (bundle == null) { mData = Nature.DATA; mUseSystemDefault = false; } else { Parcelable[] parcels = bundle.getParcelableArray(EMOJI_KEY); mData = new Emoji[parcels.length]; for (int i = 0; i < parcels.length; i++) { mData[i] = (Emoji) parcels[i]; } mUseSystemDefault = bundle.getBoolean(USE_SYSTEM_DEFAULT_KEY); } gridView.setAdapter(new EmojiAdapter(view.getContext(), mData, mUseSystemDefault)); gridView.setOnItemClickListener(this); }
}
Create a new layout containing a view pager and some component to control the view pager transition (in my case I've used a third part library called
SmartTabLayout
as shown below:<com.ogaclejapan.smarttablayout.SmartTabLayout android:id="@+id/emoji_tabs" android:layout_width="0dip" android:layout_height="40dip" android:layout_weight="1" app:stl_clickable="true" app:stl_defaultTabBackground="@color/rsc_emoji_tab_bkg" app:stl_defaultTabTextAllCaps="true" app:stl_defaultTabTextColor="#000" app:stl_defaultTabTextHorizontalPadding="0dip" app:stl_defaultTabTextMinWidth="0dp" app:stl_defaultTabTextSize="14sp" app:stl_distributeEvenly="true" app:stl_dividerColor="@color/rsc_emoji_tab_bkg" app:stl_drawDecorationAfterTab="true" app:stl_indicatorColor="@color/rsc_emoji_tab_indicator" app:stl_indicatorGravity="bottom" app:stl_indicatorInFront="false" app:stl_indicatorInterpolation="smart" app:stl_indicatorThickness="2dp" app:stl_overlineThickness="0dp" app:stl_titleOffset="24dp" app:stl_underlineThickness="0dp"/> <ImageButton android:id="@+id/backspace" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@color/rsc_emoji_tab_bkg" android:paddingLeft="10dip" android:paddingRight="10dip" android:src="@drawable/sym_keyboard_delete_holo_dark"/>
PS2: the button above exists in order to provide the backspace functionality
Part 02: Controller layer
Create an adapter to control the insertion of the emojis in the GridView, for example:
public class EmojiAdapter extends ArrayAdapter<Emoji> { private boolean mUseSystemDefault = Boolean.FALSE; // CONSTRUCTOR public EmojiAdapter(Context context, Emoji[] data) { super(context, R.layout.rsc_emoji_item, data); } public EmojiAdapter(Context context, List<Emoji> data) { super(context, R.layout.rsc_emoji_item, data); } public EmojiAdapter(Context context, List<Emoji> data, boolean useSystemDefault) { super(context, R.layout.rsc_emoji_item, data); this.mUseSystemDefault = useSystemDefault; } public EmojiAdapter(Context context, Emoji[] data, boolean useSystemDefault) { super(context, R.layout.rsc_emoji_item, data); this.mUseSystemDefault = useSystemDefault; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { view = View.inflate(getContext(), R.layout.rsc_emoji_item, null); view.setTag(new ViewHolder(view, this.mUseSystemDefault)); } Emoji emoji = this.getItem(position); ViewHolder holder = (ViewHolder) view.getTag(); holder.icon.setText(emoji.getEmoji()); return view; } static class ViewHolder { EmojiTextView icon; public ViewHolder(View view, Boolean useSystemDefault) { this.icon = (EmojiTextView) view.findViewById(R.id.emoji_icon); this.icon.setUseSystemDefault(useSystemDefault); } } }
Create classes that will inflate each one of the emoji-pages passing the emojis (following the Unicode pattern) to the GridView. i.e.:
@Override public void onViewCreated(View view, Bundle savedInstanceState) { GridView gridView = (GridView) view.findViewById(R.id.Emoji_GridView); Bundle bundle = getArguments(); if (bundle == null) { mData = Nature.DATA; mUseSystemDefault = false; } else { Parcelable[] parcels = bundle.getParcelableArray(EMOJI_KEY); mData = new Emoji[parcels.length]; for (int i = 0; i < parcels.length; i++) { mData[i] = (Emoji) parcels[i]; } mUseSystemDefault = bundle.getBoolean(USE_SYSTEM_DEFAULT_KEY); } gridView.setAdapter(new EmojiAdapter(view.getContext(), mData, mUseSystemDefault)); gridView.setOnItemClickListener(this); }
Create two classes: one that extends from EditText and another that extends from TextView. Intercept the input of each one of them to identify when the typed element is an Emoji, if so, add a spannable in order to display the icon (mainly need if you want to override the system default emojis to have something that looks like whats-app or telegram, for instance);
Handle the interaction with soft-keyboard. It can be done in two ways:
- Draw a Dialog over the soft keyboard;
- Disable the interaction of the soft keyboard with the activity and handle the screen draw yourself;
PS3: I had a hard time trying to format the code and still some of the XML is not shown, if someone can fix it I would be thankfull
回答5:
You can use this library for Android: https://github.com/rockerhieu/emojicon
回答6:
Case 1 : Custom Keypad Launched First The Keypad is Created Based on the Size of the Android Keypad , as this Keypad is Height is Unknown Initially the Custom keypad is created with a Fixed height - in this case you have to Move the Edit Area above the Custom Keypad with the Fixed Height ( Which can be used by set Padding on the Parent Layout where Edit area is placed ( parentLayout->setPadding ( 0 , 0 , 0 ,Height) ->Where height is your Initial Keypad Height). Note : Donot Forget to set the padding to 0 when the Custom Keypad is Destroyed or hidden.
case 2 : Android Text Keypad is Launched First
The Keypad is Known Write into Preferences when the Custom Keypad is Launched use this Height. No need of setting any padding cause this is what the Android Keypad Does for you.
来源:https://stackoverflow.com/questions/16768930/implementations-of-emoji-emoticon-view-keyboard-layouts