- 浏览: 19287 次
- 性别:
- 来自: 深圳
最新评论
众所周知,APP应用中带有表情功能,可以更好的提高用户体验。 OSChina.NET Android版客户端v1.6 也加入表情功能,借此机会也给大家分享一下Android的编辑框是如何插入表情图片的,欢迎大家一起交流学习。
首先,把整理好的表情图片以及布局用到的一些图片导入到项目的res/drawable目录中。
然后,编辑res/layout目录下布局.xml文件,这里我把oschina客户端的布局代码贴上来,供大家参考:
tweet_pub.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/white"> <FrameLayout android:id="@+id/tweet_pub_form" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> <EditText android:id="@+id/tweet_pub_content" android:layout_width="fill_parent" android:layout_height="fill_parent" android:autoLink="web" android:gravity="top" android:hint="请输入动弹内容" android:background="@null"/> <ImageView android:id="@+id/tweet_pub_image" android:layout_width="60.0dip" android:layout_height="45.0dip" android:layout_marginLeft="5.0dip" android:layout_marginBottom="5.0dip" android:layout_gravity="left|bottom" android:clickable="true" android:visibility="gone"/> <LinearLayout android:id="@+id/tweet_pub_clearwords" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="5.0dip" android:layout_marginBottom="5.0dip" android:layout_gravity="right|bottom" android:gravity="center" android:background="@drawable/clearwords_bg" android:clickable="true"> <TextView android:id="@+id/tweet_pub_numberwords" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/black" android:text="160"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="3dip" android:src="@drawable/clearwords_icon"/> </LinearLayout> </FrameLayout> <include layout="@layout/tweet_pub_footer"/> </LinearLayout>
tweet_pub_footer.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:background="@drawable/widget_bar_bg"> <ImageView android:id="@+id/tweet_pub_footbar_face" style="@style/main_footbar_image" android:src="@drawable/widget_bar_face"/> <ImageView style="@style/main_footbar_cutline" android:src="@drawable/widget_bar_cut_off"/> <ImageView android:id="@+id/tweet_pub_footbar_photo" style="@style/main_footbar_image" android:src="@drawable/widget_bar_photo"/> <ImageView style="@style/main_footbar_cutline" android:src="@drawable/widget_bar_cut_off"/> <ImageView android:id="@+id/tweet_pub_footbar_atme" style="@style/main_footbar_image" android:src="@drawable/widget_bar_atme"/> <ImageView style="@style/main_footbar_cutline" android:src="@drawable/widget_bar_cut_off"/> <ImageView android:id="@+id/tweet_pub_footbar_software" style="@style/main_footbar_image" android:src="@drawable/widget_bar_soft"/> </LinearLayout> <GridView android:id="@+id/tweet_pub_faces" android:layout_width="fill_parent" android:layout_height="220dip" android:numColumns="auto_fit" android:columnWidth="50dip" android:stretchMode="columnWidth" android:gravity="center" android:fadingEdge="none" android:scrollingCache="false" android:background="@color/face_bg" android:visibility="gone"/> </LinearLayout>
通过上面布局代码可以看出,我把整个编辑界面分成了2个.xml文件。主布局文件tweet_pub.xml通过<include>标签把底 部工具栏tweet_pub_footer.xml加载进视图。这样做的好处是把一个较复杂的布局细分成几个小布局,让布局更清晰,维护起来更加方便。
接下来,创建一个Activity类,并在AndroidManifest.xml中注册,对该Activity添加一个属性:
android:windowSoftInputMode="stateVisible|adjustResize"
该属性在Activity启动显示的时候,软键盘也自动弹出显示,这样方便用户可直接对EditText编辑框进行输入文字操作。
下面贴出Activity的完整代码:
public class MainActivity extends Activity { private EditText mContent; private ImageView mFace; private LinearLayout mClearwords; private TextView mNumberwords; private GridView mGridView; private GridViewFaceAdapter mGVFaceAdapter; private InputMethodManager imm; private static final int MAX_TEXT_LENGTH = 160;//最大输入字数 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.tweet_pub); //软键盘管理类 imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); //初始化基本视图 this.initView(); //初始化表情视图 this.initGridView(); } //初始化视图控件 private void initView() { mContent = (EditText)findViewById(R.id.tweet_pub_content); mFace = (ImageView)findViewById(R.id.tweet_pub_footbar_face); mClearwords = (LinearLayout)findViewById(R.id.tweet_pub_clearwords); mNumberwords = (TextView)findViewById(R.id.tweet_pub_numberwords); //设置控件点击事件 mFace.setOnClickListener(faceClickListener); mClearwords.setOnClickListener(clearwordsClickListener); //编辑器添加文本监听 mContent.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence s, int start, int before, int count) { //显示剩余可输入的字数 mNumberwords.setText((MAX_TEXT_LENGTH - s.length()) + ""); } public void beforeTextChanged(CharSequence s, int start, int count, int after) {} public void afterTextChanged(Editable s) {} }); //编辑器点击事件 mContent.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { //显示软键盘 showIMM(); } }); //设置最大输入字数 InputFilter[] filters = new InputFilter[1]; filters[0] = new InputFilter.LengthFilter(MAX_TEXT_LENGTH); mContent.setFilters(filters); } //初始化表情控件 private void initGridView() { mGVFaceAdapter = new GridViewFaceAdapter(this); mGridView = (GridView)findViewById(R.id.tweet_pub_faces); mGridView.setAdapter(mGVFaceAdapter); mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener(){ public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //插入的表情 SpannableString ss = new SpannableString(view.getTag().toString()); Drawable d = getResources().getDrawable((int)mGVFaceAdapter.getItemId(position)); d.setBounds(0, 0, 35, 35);//设置表情图片的显示大小 ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BOTTOM); ss.setSpan(span, 0, view.getTag().toString().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //在光标所在处插入表情 mContent.getText().insert(mContent.getSelectionStart(), ss); } }); } private void showIMM() { mFace.setTag(1); showOrHideIMM(); } private void showFace() { mFace.setImageResource(R.drawable.widget_bar_keyboard); mFace.setTag(1); mGridView.setVisibility(View.VISIBLE); } private void hideFace() { mFace.setImageResource(R.drawable.widget_bar_face); mFace.setTag(null); mGridView.setVisibility(View.GONE); } private void showOrHideIMM() { if(mFace.getTag() == null){ //隐藏软键盘 imm.hideSoftInputFromWindow(mFace.getWindowToken(), 0); //显示表情 showFace(); }else{ //显示软键盘 imm.showSoftInput(mContent, 0); //隐藏表情 hideFace(); } } //表情控件点击事件 private View.OnClickListener faceClickListener = new View.OnClickListener() { public void onClick(View v) { showOrHideIMM(); } }; //清除控件点击事件 private View.OnClickListener clearwordsClickListener = new View.OnClickListener() { public void onClick(View v) { String content = mContent.getText().toString(); if(content != ""){ AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext()); builder.setTitle("清除文字吗?"); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); //清除文字 mContent.setText(""); mNumberwords.setText(String.valueOf(MAX_TEXT_LENGTH)); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.show(); } } }; }
这里说明下,GridViewFaceAdapter类是我自定义的适配器类,继承了BaseAdapter。下面我也将该类的完整代码贴出来,给大家参考:
public class GridViewFaceAdapter extends BaseAdapter { // 定义Context private Context mContext; // 定义整型数组 即图片源 private int[] mImageIds; public GridViewFaceAdapter(Context c) { mContext = c; mImageIds = new int[]{ R.drawable.f001,R.drawable.f002,R.drawable.f003,R.drawable.f004,R.drawable.f005,R.drawable.f006, R.drawable.f007,R.drawable.f008,R.drawable.f009,R.drawable.f010,R.drawable.f011,R.drawable.f012, R.drawable.f013,R.drawable.f014,R.drawable.f015,R.drawable.f016,R.drawable.f017,R.drawable.f018, R.drawable.f019,R.drawable.f020,R.drawable.f021,R.drawable.f022,R.drawable.f023,R.drawable.f024, R.drawable.f025,R.drawable.f026,R.drawable.f027,R.drawable.f028,R.drawable.f029,R.drawable.f030, R.drawable.f031,R.drawable.f032,R.drawable.f033,R.drawable.f034,R.drawable.f035,R.drawable.f036, R.drawable.f037,R.drawable.f038,R.drawable.f039,R.drawable.f040,R.drawable.f041,R.drawable.f042, R.drawable.f043,R.drawable.f044,R.drawable.f045,R.drawable.f046,R.drawable.f047,R.drawable.f048, R.drawable.f049,R.drawable.f050,R.drawable.f051,R.drawable.f052,R.drawable.f053,R.drawable.f054, R.drawable.f055,R.drawable.f056,R.drawable.f057,R.drawable.f058,R.drawable.f059,R.drawable.f060, R.drawable.f061,R.drawable.f062,R.drawable.f063,R.drawable.f064,R.drawable.f065,R.drawable.f067, R.drawable.f068,R.drawable.f069,R.drawable.f070,R.drawable.f071,R.drawable.f072,R.drawable.f073, R.drawable.f074,R.drawable.f075,R.drawable.f076,R.drawable.f077,R.drawable.f078,R.drawable.f079, R.drawable.f080,R.drawable.f081,R.drawable.f082,R.drawable.f083,R.drawable.f084,R.drawable.f085, R.drawable.f086,R.drawable.f087,R.drawable.f088,R.drawable.f089,R.drawable.f090,R.drawable.f091, R.drawable.f092,R.drawable.f093,R.drawable.f094,R.drawable.f095,R.drawable.f096,R.drawable.f097, R.drawable.f098,R.drawable.f099,R.drawable.f100,R.drawable.f101,R.drawable.f103,R.drawable.f104, R.drawable.f105 }; } // 获取图片的个数 public int getCount() { return mImageIds.length; } // 获取图片在库中的位置 public Object getItem(int position) { return position; } // 获取图片ID public long getItemId(int position) { return mImageIds[position]; } public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { imageView = new ImageView(mContext); // 设置图片n×n显示 imageView.setLayoutParams(new GridView.LayoutParams(85, 85)); // 设置显示比例类型 imageView.setScaleType(ImageView.ScaleType.CENTER); } else { imageView = (ImageView) convertView; } imageView.setImageResource(mImageIds[position]); if(position < 65) imageView.setTag("["+position+"]"); else if(position < 100) imageView.setTag("["+(position+1)+"]"); else imageView.setTag("["+(position+2)+"]"); return imageView; } }
对上面GridViewFaceAdapter类的代码做下说明:
1.我将所有的表情图片对应的资源ID,用一个整数数组封装了。
2.getView方法里的下面这段代码:
imageView.setImageResource(mImageIds[position]); if(position < 65) imageView.setTag("["+position+"]"); else if(position < 100) imageView.setTag("["+(position+1)+"]"); else imageView.setTag("["+(position+2)+"]");
由于客户端用到表情图片,对应OSC网站里的表情图片不是完整的,才做了上面代码的判断处理。
OK,就这么简单。
下面附上OSC Android项目提取的源码包:
点击此处
如果大家有什么疑问的话,欢迎在下面回帖一起探讨。
PS:
OSC Android客户端下载地址:
http://www.oschina.net/uploads/osc.apk
OSC iPhone客户端下载地址:
http://www.oschina.net/uploads/osc.ipa
OSC Windows Phone客户端下载地址:
http://www.oschina.net/uploads/osc.xap
转载:http://www.oschina.net/question/157182_65855
发表评论
-
开源中国 4 周年, Android、iPhone、WP7三个平台客户端全面开源
2012-08-31 10:26 10132008年8月31日,OSChina 网站正式上线,到今天刚好 ... -
【OSC手机App技术解析】- Android完全退出程序
2012-07-23 15:25 748做过Android开发的人都知道,应用程序点击返回键 或者 代 ... -
【OSC手机App技术解析】- 列表异步线程加载图片
2012-07-23 15:16 1216手机客户端以列表形式展示数据是非常常见的一种方式。然而列表中要 ... -
【OSC手机App技术解析】- 气泡对话列表
2012-07-18 11:47 994在OSC 的Windows Phone以及Andro ... -
【OSC手机App技术解析】- 富文本列表的展示
2012-07-18 11:38 959大家都知道OSC 的网页动态显示是需要多种颜色的才能达到需要 ... -
【OSC手机App技术解析】- 用户通知
2012-07-11 16:31 713大家在使用OSC的手机客户端的过程中,很可能也会收到来自服 ... -
【OSC手机App技术解析】- 集成新浪微博Android SDK
2012-07-10 15:02 1203使用 OSChina.NET Android ... -
【OSC手机App技术解析】- 在WebView中组装HTML
2012-07-10 13:30 1014上一篇我们介绍了 OSChin ... -
【OSC手机App技术解析】- 应用内Web链接的处理
2012-07-08 16:29 732在OSChina.NET手机客户端上显示资讯,最好的方案就是用 ...
相关推荐
Gnome-OSC-HS--2-themes,包含Gnome-OSC-HS-(transparent)和Gnome-OSC-HS-(transparent),用于Ubuntu 18.04,仿mac风格,直接放入/usr/share/themes下就可以了使用
官方离线安装包,亲测可用
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
Gnome-OSC-HS--2-themes.tar.xz ubuntu18.04 仿 mac 主题
《Python库osc-placement详解》 在Python的世界里,丰富的库是其强大功能的重要支撑。本文将深入探讨一个名为"osc-placement"的Python库,版本为1.5.0,它被封装在一个名为"osc-placement-1.5.0.tar.gz"的压缩包中...
OSC振荡器有源无源晶体晶振AD封装库Altium封装库三维视图PCB封装库(3D封装库),52个封装,PcbLibb后缀文件,封装列表如下: Component Count : 52 Component Name ----------------------------------------------- ...
【标题】"mumu-osc-nicefish-ionic-master_ionic_agou3k_移动端" 指的是一款基于 Ionic 框架开发的移动应用项目,该项目在 "mumu-osc" 开源社区中被创建,并且由 "agou3k" 进行了维护。"nicefish-ionic" 是此项目的...
【pt-osc在线重建表导致死锁的分析及优化方案】 在进行数据库维护时,特别是在业务低峰期使用像pt-online-schema-change(pt-osc)这样的工具进行在线DDL操作时,可能会遇到死锁问题,这可能导致业务SQL被回滚,...
python库。 资源全名:osc-docker-builder-1.7.tar.gz
"mumu-osc-OpenWMS-Frontend-master_back_示范_"这个标题表明这是一个与OpenWMS(开放仓库管理系统)前端相关的项目,可能是某个开发者或团队为了展示后端管理系统的最佳实践而创建的一个备份示例。"back"标签强调了...
OSC 455E-LI OSC 455E-WI OSC 1612-4P OSC 2025-4P OSC 3215-2P OSC 3225-4P OSC 4025-4P OSC 5032-2P OSC 5032-4P OSC 6035-2P OSC 6035-4P OSC 7050-2P OSC 7050-4P OSC 8045-2P OSC 8045-4P OSC 8045-4P-C OSC HC...
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
OSC 455E-LI OSC 455E-WI OSC 1612-4P OSC 2025-4P OSC 3215-2P OSC 3225-4P OSC 4025-4P OSC 5032-2P OSC 5032-4P OSC 6035-2P OSC 6035-4P OSC 7050-2P OSC 7050-4P OSC 8045-2P OSC 8045-4P OSC 8045-4P-C OSC HC...
OSC 455E-LI OSC 455E-WI OSC 1612-4P OSC 2025-4P OSC 3215-2P OSC 3225-4P OSC 4025-4P OSC 5032-2P OSC 5032-4P OSC 6035-2P OSC 6035-4P OSC 7050-2P OSC 7050-4P OSC 8045-2P OSC 8045-4P OSC 8045-4P-C OSC HC...
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
离线安装包,亲测可用
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
【标题】"osc-android-app2.0改动一下" 指的是开源中国(Open Source China)的Android应用程序的2.0版本进行了一些更新和优化,以便兼容Android Studio 1.3的Preview 2.0版本。这个过程通常涉及到对源代码的修改、...