作为刚刚初出茅庐的不到四个月初生牛犊,因为平时公司项目比较少,给了新人相当多的时间学习,所以我就在研究了一下即时通讯软件,最近一个礼拜的时间进度都堵在了表情模块这一部分,所以我就将自己这一个礼拜以来的相关问题进行一个总结,以便和大家分享讨论,这里先上效果图:
实现最终效果我打算分为三步来写:
一、组织结构(布局);
二、数据的获取;
三、整合资源实现效果。
一、首先看看整个Activity的布局,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:id="@+id/main"
android:orientation="vertical" >
<!-- TopBar -->
<RelativeLayout
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/title_bar">
<!-- TopBar 返回键 -->
<ImageView
android:id="@+id/chart_title_bar_back"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/mm_submenu_normal"
android:layout_margin="10dp"
android:layout_alignParentLeft="true"
android:scaleType="fitXY"/>
<!-- TopBar 竖线 -->
<ImageView
android:id="@+id/chart_title_bar_line"
android:layout_width="1dp"
android:layout_height="match_parent"
android:src="@drawable/chat_footer_bg"
android:layout_toRightOf="@+id/chart_title_bar_back"
android:layout_alignTop="@+id/chart_title_bar_back"
android:layout_alignBottom="@+id/chart_title_bar_back"
android:scaleType="fitXY"/>
<!-- TopBar 聊天对象 -->
<TextView
android:id="@+id/chart_title_bar_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="XF"
android:textSize="16sp"
android:textColor="#ffffff"
android:gravity="left|center_vertical"
android:layout_marginLeft="5dp"
android:layout_toRightOf="@+id/chart_title_bar_line"
android:layout_alignTop="@+id/chart_title_bar_line"
android:layout_alignBottom="@+id/chart_title_bar_line"/>
<!-- TopBar 右上角头像 -->
<ImageView
android:id="@+id/chart_title_bar_person"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/mm_title_btn_contact_normal"
android:layout_alignParentRight="true"
android:layout_margin="10dp"
android:scaleType="fitXY"/>
</RelativeLayout>
<!-- 聊天内容区 -->
<ListView
android:id="@+id/chart_listView"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:divider="@null"
android:dividerHeight="10dp"
android:background="#eeeeee">
</ListView>
<!-- 分割线 -->
<View android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#ccc"/>
<!-- bottombar 编辑栏 -->
<RelativeLayout
android:id="@+id/buttom_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="6dp"
android:background="#ffffff">
<!-- 文本输入框 -->
<include
android:id="@+id/chart_bottombar_EditText"
layout="@layout/chart_bottombar_tedittext"
android:visibility="visible"/>
<!-- 录音符号图片 -->
<ImageView
android:id="@+id/chart_bottom_bar_choose"
android:layout_width="30dp"
android:layout_height="37dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_gravity="left|bottom"
android:layout_marginBottom="7dp"
android:layout_alignBottom="@+id/chart_bottombar_EditText"
android:src="@drawable/bottom_recorder"
android:scaleType="centerInside"/>
<!-- 添加符号图片 -->
<ImageView
android:id="@+id/chart_bottom_bar_add"
android:layout_width="30dp"
android:layout_height="37dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_gravity="bottom"
android:layout_marginBottom="7dp"
android:layout_alignParentRight="true"
android:layout_alignBottom="@+id/chart_bottombar_EditText"
android:src="@drawable/bottom_add"
android:scaleType="centerInside"/>
<!-- 发送按钮 -->
<Button
android:id="@+id/chart_bottom_bar_send"
android:layout_width="40dp"
android:layout_height="37dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_gravity="bottom"
android:layout_marginBottom="7dp"
android:layout_alignParentRight="true"
android:layout_alignBottom="@+id/chart_bottombar_EditText"
android:text="发送"
android:textColor="#ffffff"
android:gravity="center"
android:background="@drawable/bottombar_btn_send"
android:visibility="gone"/>
</RelativeLayout>
<!-- 表情区 -->
<fragment
android:id="@+id/chart_smile_Fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
class="com.example.addsmile.fragment.ChartSmileFragment"
android:visibility="visible"/>
</LinearLayout>
我已经对每个View都做了备注,所以这里直接挑重点,继续带大家看看我们本文的主题——表情内容区:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/chart_emoji"
android:background="#ffffff"
>
<!-- 分割线 -->
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#ccc"/>
<!-- 表情存储区 -->
<android.support.v4.view.ViewPager
android:id="@+id/chart_emoji_Viewpager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
</android.support.v4.view.ViewPager>
<!-- 表情存储区的指示器区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginBottom="3dp">
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator1"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator2"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator3"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator4"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator5"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator6"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator7"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator8"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator9"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
<!-- ViewPager页码指示器 -->
<ImageButton
android:id="@+id/emoji_pager_indicator10"
android:layout_width="8dp"
android:layout_height="8dp"
android:src="@drawable/nim_view_pager_indicator_selector"
android:scaleType="fitCenter"/>
</LinearLayout>
<!-- 分割线 -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#ccc"/>
<!-- 表情分类区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="left|center_vertical"
android:weightSum="7">
<!-- 表情类型 -->
<ImageView
android:id="@+id/emoji_eump_A"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="30dp"
android:padding="4dp"
android:src="@drawable/emoji_icon_selector"
android:scaleType="centerInside"
android:background="@drawable/emoji_icon_selector_bg"/>
<!-- 表情类型 -->
<ImageView
android:id="@+id/emoji_eump_B"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="30dp"
android:padding="4dp"
android:src="@drawable/emoji_ajmds_selector"
android:scaleType="centerInside"
android:background="@drawable/emoji_icon_selector_bg"/>
<!-- 表情类型 -->
<ImageView
android:id="@+id/emoji_eump_C"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="30dp"
android:padding="4dp"
android:src="@drawable/emoji_xxys_selector"
android:scaleType="centerInside"
android:background="@drawable/emoji_icon_selector_bg"/>
<!-- 表情类型 -->
<ImageView
android:id="@+id/emoji_eump_D"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="30dp"
android:padding="4dp"
android:src="@drawable/emoji_lts_selector"
android:scaleType="centerInside"
android:background="@drawable/emoji_icon_selector_bg"/>
</LinearLayout>
</LinearLayout>
如果大家是看源码的话,看到这里应该会有一个疑问,先上一张布局效果图给大家。
根据源码和效果图上面的框架图大家应该可以看到,现在效果图上面只有分割线和ViewPager,其它内容都没有显示出来,这是否意味着我们的布局有问题呢?这里只是我们遇到的第一个难题,ViewPager的高度自适应。我在解决这个问题的时候,曾经对大神的文章进行过注解,大家可以看看我写的这篇文章:ViewPager高度自适应。
接着,我们对ViewPager里面的Fragment分析一下怎么实现?这个很明显只有一个Gridview控件。我使用的是最快捷的笨办法,放了两个不同xml文件,来存储28个表情的Fragment和8个表情的Fragment。不过大家在这里可以考虑根据参数动态的修改Gridview的参数或者放置两个不同参数的GridView控件,然后根据参数隐藏一个即可。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical" >
<GridView
android:id="@+id/gview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="auto_fit"
android:columnWidth="28dp"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp"
android:horizontalSpacing="22dp"
android:padding="5dp">
</GridView>
</LinearLayout>
二、数据的获取,这个为什么需要单独的提出来讲呢?有两个原因。第一,是因为大家看见我们的Fragment是静态的加载,即Activity在setContentView这个方法时就需要对Fragment进行加载,所以我们必须在加载这个方法之前得到数据,但问题是我加载assets里面的图片需要Context对象,而此时是没有的。我在本文的处理是新开一个准备的Activity来加载数据,完成加载之后才打开我们Fragment依托的这个Activity。
第二,如果只是准备把ViewPager把图片放进去而不考虑后面的EditText控件显示的话,只需要看读取assets下面的图片这篇文章即可,但是我们最后需要EditText控件显示图片,所以这里有几个步骤和《读取assets下面的图片》不同。这里先上代码:
/**
* 加载Assets下面的图片数据并将emoji类型的表情排序
* @param mContext
*/
public static void addValue(Context mContext)
{
long time = System.currentTimeMillis();
InputStream inputStream;
try {
inputStream = mContext.getResources().getAssets()
.open("emoji/emoji.xml");
Const.smiles = ParserEmoji.getSmiles(inputStream);
}
catch (Exception e) {
e.printStackTrace();
}
List<Bitmap> dataA = new ArrayList<Bitmap>();
Log.i("Smile", "Const.smiles:"+Const.smiles.size());
for (int i = 0; i < Const.smiles.size(); i++)
{
Bitmap bmp = Utils.getBitmapFromAssetsFile(mContext, "emoji/default/"+Const.smiles.get(i).getFile());
dataA.add(bmp);
}
int sizeA = Utils.dataA.size();
Const.smileData.add(dataA);
List<Bitmap> dataB = Utils.scanSpecifyFile(mContext, Const.ASSETS_TYPE_AJMD);
Const.smileData.add(dataB);
int sizeB = dataB.size();
Utils.bitmapData = new ArrayList<Bitmap>();
List<Bitmap> dataC = Utils.scanSpecifyFile(mContext, Const.ASSETS_TYPE_XXY);
Const.smileData.add(dataC);
int sizeC = dataC.size();
Utils.bitmapData = new ArrayList<Bitmap>();
List<Bitmap> dataD = Utils.scanSpecifyFile(mContext, Const.ASSETS_TYPE_LT);
Const.smileData.add(dataD);
int sizeD = dataD.size();
Utils.bitmapData = new ArrayList<Bitmap>();
time = (System.currentTimeMillis()-time)/1000;
int size = sizeA+sizeB+sizeC+sizeD;
Log.i("Smile", "MyApplication数据加载结束,耗时:"+time+"图片数量:"+size);
}
通过代码我们可以看到,emoji类型的表情图片和其它类型的表情图片不一样,不是直接通过路径获取,而是通过解析xml文件,然后得到实体类Smile的集合,最后对集合进行遍历使用路径加图片名称获取到一个根据xml文件排序的Bitmap集合。
xml文件:
<?xml version="1.0" encoding="utf-8"?>
<PopoEmoticons>
<Catalog Title="default">
<Emoticon ID="emoticon_emoji_01" Tag="[可爱]" File="emoji_01.png" />
<Emoticon ID="emoticon_emoji_0" Tag="[大笑]" File="emoji_00.png" />
<Emoticon ID="emoticon_emoji_02" Tag="[色]" File="emoji_02.png" />
<Emoticon ID="emoticon_emoji_03" Tag="[嘘]" File="emoji_03.png" />
<Emoticon ID="emoticon_emoji_04" Tag="[亲]" File="emoji_04.png" />
<Emoticon ID="emoticon_emoji_05" Tag="[呆]" File="emoji_05.png" />
<Emoticon ID="emoticon_emoji_06" Tag="[口水]" File="emoji_06.png" />
<Emoticon ID="emoticon_emoji_145" Tag="[汗]" File="emoji_145.png" />
<Emoticon ID="emoticon_emoji_07" Tag="[呲牙]" File="emoji_07.png" />
<Emoticon ID="emoticon_emoji_08" Tag="[鬼脸]" File="emoji_08.png" />
<Emoticon ID="emoticon_emoji_09" Tag="[害羞]" File="emoji_09.png" />
<Emoticon ID="emoticon_emoji_10" Tag="[偷笑]" File="emoji_10.png" />
<Emoticon ID="emoticon_emoji_11" Tag="[调皮]" File="emoji_11.png" />
<Emoticon ID="emoticon_emoji_12" Tag="[可怜]" File="emoji_12.png" />
<Emoticon ID="emoticon_emoji_13" Tag="[敲]" File="emoji_13.png" />
<Emoticon ID="emoticon_emoji_14" Tag="[惊讶]" File="emoji_14.png" />
<Emoticon ID="emoticon_emoji_15" Tag="[流感]" File="emoji_15.png" />
<Emoticon ID="emoticon_emoji_16" Tag="[委屈]" File="emoji_16.png" />
<Emoticon ID="emoticon_emoji_17" Tag="[流泪]" File="emoji_17.png" />
<Emoticon ID="emoticon_emoji_18" Tag="[嚎哭]" File="emoji_18.png" />
<Emoticon ID="emoticon_emoji_19" Tag="[惊恐]" File="emoji_19.png" />
<Emoticon ID="emoticon_emoji_20" Tag="[怒]" File="emoji_20.png" />
<Emoticon ID="emoticon_emoji_21" Tag="[酷]" File="emoji_21.png" />
<Emoticon ID="emoticon_emoji_22" Tag="[不说]" File="emoji_22.png" />
<Emoticon ID="emoticon_emoji_23" Tag="[鄙视]" File="emoji_23.png" />
<Emoticon ID="emoticon_emoji_24" Tag="[阿弥陀佛]" File="emoji_24.png" />
<Emoticon ID="emoticon_emoji_25" Tag="[奸笑]" File="emoji_25.png" />
<Emoticon ID="emoticon_emoji_26" Tag="[睡着]" File="emoji_26.png" />
<Emoticon ID="emoticon_emoji_27" Tag="[口罩]" File="emoji_27.png" />
<Emoticon ID="emoticon_emoji_28" Tag="[努力]" File="emoji_28.png" />
<Emoticon ID="emoticon_emoji_29" Tag="[抠鼻孔]" File="emoji_29.png" />
<Emoticon ID="emoticon_emoji_30" Tag="[疑问]" File="emoji_30.png" />
<Emoticon ID="emoticon_emoji_31" Tag="[怒骂]" File="emoji_31.png" />
<Emoticon ID="emoticon_emoji_32" Tag="[晕]" File="emoji_32.png" />
<Emoticon ID="emoticon_emoji_33" Tag="[呕吐]" File="emoji_33.png" />
<Emoticon ID="emoticon_emoji_160" Tag="[拜一拜]" File="emoji_160.png" />
<Emoticon ID="emoticon_emoji_161" Tag="[惊喜]" File="emoji_161.png" />
<Emoticon ID="emoticon_emoji_162" Tag="[流汗]" File="emoji_162.png" />
<Emoticon ID="emoticon_emoji_163" Tag="[卖萌]" File="emoji_163.png" />
<Emoticon ID="emoticon_emoji_164" Tag="[默契眨眼]" File="emoji_164.png" />
<Emoticon ID="emoticon_emoji_165" Tag="[烧香拜佛]" File="emoji_165.png" />
<Emoticon ID="emoticon_emoji_166" Tag="[晚安]" File="emoji_166.png" />
<Emoticon ID="emoticon_emoji_34" Tag="[强]" File="emoji_34.png" />
<Emoticon ID="emoticon_emoji_35" Tag="[弱]" File="emoji_35.png" />
<Emoticon ID="emoticon_emoji_36" Tag="[OK]" File="emoji_36.png" />
<Emoticon ID="emoticon_emoji_37" Tag="[拳头]" File="emoji_37.png" />
<Emoticon ID="emoticon_emoji_38" Tag="[胜利]" File="emoji_38.png" />
<Emoticon ID="emoticon_emoji_39" Tag="[鼓掌]" File="emoji_39.png" />
<Emoticon ID="emoticon_emoji_167" Tag="[握手]" File="emoji_167.png" />
<Emoticon ID="emoticon_emoji_40" Tag="[发怒]" File="emoji_40.png" />
<Emoticon ID="emoticon_emoji_41" Tag="[骷髅]" File="emoji_41.png" />
<Emoticon ID="emoticon_emoji_42" Tag="[便便]" File="emoji_42.png" />
<Emoticon ID="emoticon_emoji_43" Tag="[火]" File="emoji_43.png" />
<Emoticon ID="emoticon_emoji_44" Tag="[溜]" File="emoji_44.png" />
<Emoticon ID="emoticon_emoji_45" Tag="[爱心]" File="emoji_45.png" />
<Emoticon ID="emoticon_emoji_46" Tag="[心碎]" File="emoji_46.png" />
<Emoticon ID="emoticon_emoji_47" Tag="[钟情]" File="emoji_47.png" />
<Emoticon ID="emoticon_emoji_48" Tag="[唇]" File="emoji_48.png" />
<Emoticon ID="emoticon_emoji_49" Tag="[戒指]" File="emoji_49.png" />
<Emoticon ID="emoticon_emoji_50" Tag="[钻石]" File="emoji_50.png" />
<Emoticon ID="emoticon_emoji_51" Tag="[太阳]" File="emoji_51.png" />
<Emoticon ID="emoticon_emoji_52" Tag="[有时晴]" File="emoji_52.png" />
<Emoticon ID="emoticon_emoji_53" Tag="[多云]" File="emoji_53.png" />
<Emoticon ID="emoticon_emoji_54" Tag="[雷]" File="emoji_54.png" />
<Emoticon ID="emoticon_emoji_55" Tag="[雨]" File="emoji_55.png" />
<Emoticon ID="emoticon_emoji_56" Tag="[雪花]" File="emoji_56.png" />
<Emoticon ID="emoticon_emoji_57" Tag="[爱人]" File="emoji_57.png" />
<Emoticon ID="emoticon_emoji_58" Tag="[帽子]" File="emoji_58.png" />
<Emoticon ID="emoticon_emoji_59" Tag="[皇冠]" File="emoji_59.png" />
<Emoticon ID="emoticon_emoji_60" Tag="[篮球]" File="emoji_60.png" />
<Emoticon ID="emoticon_emoji_61" Tag="[足球]" File="emoji_61.png" />
<Emoticon ID="emoticon_emoji_62" Tag="[垒球]" File="emoji_62.png" />
<Emoticon ID="emoticon_emoji_63" Tag="[网球]" File="emoji_63.png" />
<Emoticon ID="emoticon_emoji_64" Tag="[台球]" File="emoji_64.png" />
<Emoticon ID="emoticon_emoji_65" Tag="[咖啡]" File="emoji_65.png" />
<Emoticon ID="emoticon_emoji_66" Tag="[啤酒]" File="emoji_66.png" />
<Emoticon ID="emoticon_emoji_67" Tag="[干杯]" File="emoji_67.png" />
<Emoticon ID="emoticon_emoji_68" Tag="[柠檬汁]" File="emoji_68.png" />
<Emoticon ID="emoticon_emoji_69" Tag="[餐具]" File="emoji_69.png" />
<Emoticon ID="emoticon_emoji_70" Tag="[汉堡]" File="emoji_70.png" />
<Emoticon ID="emoticon_emoji_71" Tag="[鸡腿]" File="emoji_71.png" />
<Emoticon ID="emoticon_emoji_72" Tag="[面条]" File="emoji_72.png" />
<Emoticon ID="emoticon_emoji_73" Tag="[冰淇淋]" File="emoji_73.png" />
<Emoticon ID="emoticon_emoji_74" Tag="[沙冰]" File="emoji_74.png" />
<Emoticon ID="emoticon_emoji_75" Tag="[生日蛋糕]" File="emoji_75.png" />
<Emoticon ID="emoticon_emoji_76" Tag="[蛋糕]" File="emoji_76.png" />
<Emoticon ID="emoticon_emoji_77" Tag="[糖果]" File="emoji_77.png" />
<Emoticon ID="emoticon_emoji_78" Tag="[葡萄]" File="emoji_78.png" />
<Emoticon ID="emoticon_emoji_79" Tag="[西瓜]" File="emoji_79.png" />
<Emoticon ID="emoticon_emoji_80" Tag="[光碟]" File="emoji_80.png" />
<Emoticon ID="emoticon_emoji_81" Tag="[手机]" File="emoji_81.png" />
<Emoticon ID="emoticon_emoji_82" Tag="[电话]" File="emoji_82.png" />
<Emoticon ID="emoticon_emoji_83" Tag="[电视]" File="emoji_83.png" />
<Emoticon ID="emoticon_emoji_84" Tag="[声音开启]" File="emoji_84.png" />
<Emoticon ID="emoticon_emoji_85" Tag="[声音关闭]" File="emoji_85.png" />
<Emoticon ID="emoticon_emoji_86" Tag="[铃铛]" File="emoji_86.png" />
<Emoticon ID="emoticon_emoji_87" Tag="[锁头]" File="emoji_87.png" />
<Emoticon ID="emoticon_emoji_88" Tag="[放大镜]" File="emoji_88.png" />
<Emoticon ID="emoticon_emoji_89" Tag="[灯泡]" File="emoji_89.png" />
<Emoticon ID="emoticon_emoji_90" Tag="[锤头]" File="emoji_90.png" />
<Emoticon ID="emoticon_emoji_91" Tag="[烟]" File="emoji_91.png" />
<Emoticon ID="emoticon_emoji_92" Tag="[炸弹]" File="emoji_92.png" />
<Emoticon ID="emoticon_emoji_93" Tag="[枪]" File="emoji_93.png" />
<Emoticon ID="emoticon_emoji_94" Tag="[刀]" File="emoji_94.png" />
<Emoticon ID="emoticon_emoji_95" Tag="[药]" File="emoji_95.png" />
<Emoticon ID="emoticon_emoji_96" Tag="[打针]" File="emoji_96.png" />
<Emoticon ID="emoticon_emoji_97" Tag="[钱袋]" File="emoji_97.png" />
<Emoticon ID="emoticon_emoji_98" Tag="[钞票]" File="emoji_98.png" />
<Emoticon ID="emoticon_emoji_99" Tag="[银行卡]" File="emoji_99.png" />
<Emoticon ID="emoticon_emoji_100" Tag="[手柄]" File="emoji_100.png" />
<Emoticon ID="emoticon_emoji_101" Tag="[麻将]" File="emoji_101.png" />
<Emoticon ID="emoticon_emoji_102" Tag="[调色板]" File="emoji_102.png" />
<Emoticon ID="emoticon_emoji_103" Tag="[电影]" File="emoji_103.png" />
<Emoticon ID="emoticon_emoji_104" Tag="[麦克风]" File="emoji_104.png" />
<Emoticon ID="emoticon_emoji_105" Tag="[耳机]" File="emoji_105.png" />
<Emoticon ID="emoticon_emoji_106" Tag="[音乐]" File="emoji_106.png" />
<Emoticon ID="emoticon_emoji_107" Tag="[吉他]" File="emoji_107.png" />
<Emoticon ID="emoticon_emoji_108" Tag="[火箭]" File="emoji_108.png" />
<Emoticon ID="emoticon_emoji_109" Tag="[飞机]" File="emoji_109.png" />
<Emoticon ID="emoticon_emoji_110" Tag="[火车]" File="emoji_110.png" />
<Emoticon ID="emoticon_emoji_111" Tag="[公交]" File="emoji_111.png" />
<Emoticon ID="emoticon_emoji_112" Tag="[轿车]" File="emoji_112.png" />
<Emoticon ID="emoticon_emoji_113" Tag="[出租车]" File="emoji_113.png" />
<Emoticon ID="emoticon_emoji_114" Tag="[警车]" File="emoji_114.png" />
<Emoticon ID="emoticon_emoji_115" Tag="[自行车]" File="emoji_115.png" />
</Catalog>
</PopoEmoticons>
Smile的实体:
package com.example.addsmile.entity;
public class Smile
{
String id;
String tag;
String file;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
}
最后是解析,由于我们平时解析的Json比较多,xml解析已经很少用了,而且一般解析xml的方法比如郭神的《第一行代码》都是简单的教我们解析下面这种文件,但是我们上面这种格式的解析,百度是基本上没有的。(反正我是没有找到,或许其它地方有资源,但是实现了就没有深究了)
<?xml version="1.0" encoding="utf-8"?>
<brows>
<brow>
<code><![CDATA[[em:1:]]]></code>
<name>f001</name>
</brow>
<brow>
<code><![CDATA[[em:2:]]]></code>
<name>f002</name>
</brow>
<brow>
<code><![CDATA[[em:3:]]]></code>
<name>f003</name>
</brow>
<brows>
最后我也是看通过百度查到一些API,然后将这些API拿来一试正好搞定。先看原创代码:
package com.example.addsmile.utils;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlPullParser;
import android.util.Log;
import android.util.Xml;
import com.example.addsmile.entity.Smile;
/**
* 用SAX解析XML采用的是从上而下的基于事件驱动的解析方式,在解析过程中会视情况自动调用
* startDocument()、startElement()、characters()、endElement()、endDocument()等相关的方法
* @author weixing
*
*/
public class ParserEmoji extends DefaultHandler
{
private static List<Smile> smiles = null ;
private Smile smile = null;
public static List<Smile> getSmiles(InputStream xmlStream) throws Exception
{
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
ParserEmoji handler = new ParserEmoji();
parser.parse(xmlStream, handler);
return smiles;
}
public List<Smile> getSmiles()
{
return smiles;
}
//只会在文档开始解析的时候被调用,每次解析只会调用一次。
@Override
public void startDocument() throws SAXException
{
smiles = new ArrayList<Smile>();
}
//每次在开始解析一个元素,即遇到元素标签开始的时候都会调用。
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException
{
if("Emoticon".equals(qName)){
smile = new Smile();
//保存元素第一个属性值
smile.setId(attributes.getValue(0));
//保存元素第二个属性值
smile.setTag(attributes.getValue(1));
//保存元素第三个属性值
smile.setFile(attributes.getValue(2));
}
}
//每次解析到元素标签携带的内容时都会调用,即使该元素标签的内容为空或换行。
//而且如果元素内嵌套元素,在父元素结束标签前, characters()方法会再次被调用,此处需要注意。
@Override
public void characters(char[] ch, int start, int length)
throws SAXException
{
}
//每次在结束解析一个元素,即遇到元素标签结束的时候都会调用。
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException
{
if(smile!=null)
{
if(smile.getFile()!=null)
smiles.add(smile);
}
Log.i("Smile", "smiles:"+smiles.size());
smile = null;
}
}
这里重点要讲的是解析属性值:
//保存元素第一个属性值
smile.setId(attributes.getValue(0));
//保存元素第二个属性值
smile.setTag(attributes.getValue(1));
//保存元素第三个属性值
smile.setFile(attributes.getValue(2));
OK,数据已经完成加载了。
三、接下来我们就可以实现最终的效果了。还是按照正常流程,我们先对Activity布局文件下的ChartSmileFragment进行梳理,看看他是怎么工作的?
首先看全局代码:
package com.example.addsmile.fragment;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.example.addsmile.OnSendEmojiIconListener;
import com.example.addsmile.adapter.MyFragmentAdapter;
import com.example.addsmile.entity.Smile;
import com.example.addsmile.utils.Const;
import com.example.test.R;
public class ChartSmileFragment extends Fragment implements OnClickListener
{
/**
* emoji表情类型
*/
private static final int SMILE_TYPE_EMOJI = 250;
/**
* ajmd表情类型
*/
private static final int SMILE_TYPE_AJMD = 300;
/**
* lt表情类型
*/
private static final int SMILE_TYPE_LT = 350;
/**
* xxy表情类型
*/
private static final int SMILE_TYPE_XXY = 400;
/**
* 表情类型
* @author Administrator
*
*/
public enum smileType{
SMILE_TYPE_EMOJI,SMILE_TYPE_AJMD,SMILE_TYPE_LT,SMILE_TYPE_XXY};
/**
* 整体视图
*/
private View layout;
/**
* ViewPager部分
*/
private ViewPager viewPager;
/**
* ViewPager指示器
*/
private ImageButton indicatorButton1,indicatorButton2,indicatorButton3,
indicatorButton4,indicatorButton5,indicatorButton6,indicatorButton7,
indicatorButton8,indicatorButton9,indicatorButton10;
/**
* ViewPager内容选择器
*/
private ImageView smile_emoji,smile_ajmd,smile_lt,smile_xxy;
/**
* emoji选择器的数据
*/
private List<Bitmap> emojidata = new ArrayList<Bitmap>();
/**
* ajmd选择器的数据
*/
private List<Bitmap> ajmddata = new ArrayList<Bitmap>();
/**
* xxy选择器的数据
*/
private List<Bitmap> xxydata = new ArrayList<Bitmap>();
/**
* lt选择器的数据
*/
private List<Bitmap> ltdata = new ArrayList<Bitmap>();
/**
* 枚举各内容的pager指示器数量
*/
private int enumemoji,enumajmd,enumxxy,enumlt;
/**
* 枚举各内容的活动区间
*/
private int enumEomjiVolume,enumAjmdVolume,enumLtVolume,enumXxyVolume;
/**
* 当前选择的状态
*/
private smileType type;
/**
* 为了记录改变状态的比对状态
*/
private smileType compareType = smileType.SMILE_TYPE_EMOJI;
/**
* 当前ViewPager的页码
*/
private int currentIndexPager = 0;
/**
* Fragment的数据源,即emojiFragment各个碎片的数据
*/
private List<Bitmap> emojiDataA,emojiDataB,emojiDataC,emojiDataD,emojiDataE,
ajmdDataA,ajmdDataB,ajmdDataC,ajmdDataD,ajmdDataE,ajmdDataF,
xxyDataA,xxyDataB,xxyDataC,xxyDataD,xxyDataE,
ltDataA,ltDataB,ltDataC;
/**
* 装载表情图片的Fragment
*/
private List<Fragment> emojiFragmentData = new ArrayList<Fragment>();
/**
* 默认的ViewPager高度
*/
private int ViewPagerheightCount = 0;
/**
* 发送表情的监听事件
*
*/
private OnSendEmojiIconListener listener;
private Handler handler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
if(msg.what==250)
{
Log.i("Smile", "收到发送表情信号");
sendSmile(msg.arg1);
}else
{
ViewPagerheightCount++;
if(ViewPagerheightCount==1)
{
setViewPagerWrapContentHeight(msg.what);
}
}
}
/**
* 发送表情图片
*/
private void sendSmile(int index)
{
if(type==smileType.SMILE_TYPE_EMOJI)
{//只需要直接显示在edittext
Smile smile = null;
boolean del = false;
switch (viewPager.getCurrentItem()) {
case 0:
//首先得到当前用户点击的表情的信息
Log.i("tag", "index----->"+index+"emojiDataA"+emojiDataA.size());
smile = Const.smiles.get(index);
if(index+1==emojiDataA.size())
{
del = false;
smile = null;
}
break;
case 1:
Log.i("tag", "index----->"+index+"emojiDataB"+emojiDataB.size());
smile = Const.smiles.get(27+index);
if(index+1==emojiDataB.size())
{
del = true;
smile = null;
}
break;
case 2:
Log.i("tag", "index----->"+index+"emojiDataC"+emojiDataC.size());
smile = Const.smiles.get(54+index);
if(index+1==emojiDataC.size())
{
del = true;
smile = null;
}
break;
case 3:
Log.i("tag", "index----->"+index+"emojiDataD"+emojiDataD.size());
smile = Const.smiles.get(81+index);
if(index+1==emojiDataD.size())
{
del = true;
smile = null;
}
break;
case 4:
Log.i("tag", "index----->"+index+"emojiDataE"+emojiDataE.size());
if(index+1==emojiDataE.size())
{
del = true;
smile = null;
}else
{
smile = Const.smiles.get(108+index);
}
break;
}
listener.chartSmileFragmnetToActivity(del,smile);
}else
{
switch (type) {
case SMILE_TYPE_AJMD :
break;
case SMILE_TYPE_XXY :
break;
case SMILE_TYPE_LT :
break;
default:
break;
}
}
};
};
public void setOnSendEmojiIconListener(OnSendEmojiIconListener listener)
{
this.listener = listener;
}
/**
* 当前主界面
*/
private LinearLayout main;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
layout = inflater.inflate(R.layout.chart_emoji, container,false);
initView();
initFragmentData();
initFragment();
initViewPager();
return layout;
}
private void initViewPager()
{
MyFragmentAdapter adapter = new MyFragmentAdapter(getChildFragmentManager(), emojiFragmentData);
viewPager.setAdapter(adapter);
}
private void initFragment()
{
//emojiFragment
Fragment emojiFragmentA = new SmileFragment(getActivity(), emojiDataA,handler,true);
Fragment emojiFragmentB = new SmileFragment(getActivity(), emojiDataB,handler,true);
Fragment emojiFragmentC = new SmileFragment(getActivity(), emojiDataC,handler,true);
Fragment emojiFragmentD = new SmileFragment(getActivity(), emojiDataD,handler,true);
Fragment emojiFragmentE = new SmileFragment(getActivity(), emojiDataE,handler,true);
//ajmdFragment
Fragment ajmdFragmentA = new SmileFragment(getActivity(), ajmdDataA,handler,false);
Fragment ajmdFragmentB = new SmileFragment(getActivity(), ajmdDataB,handler,false);
Fragment ajmdFragmentC = new SmileFragment(getActivity(), ajmdDataC,handler,false);
Fragment ajmdFragmentD = new SmileFragment(getActivity(), ajmdDataD,handler,false);
Fragment ajmdFragmentE = new SmileFragment(getActivity(), ajmdDataE,handler,false);
Fragment ajmdFragmentF = new SmileFragment(getActivity(), ajmdDataE,handler,false);
//ajmdFragment
Fragment xxyFragmentA = new SmileFragment(getActivity(), xxyDataA,handler,false);
Fragment xxyFragmentB = new SmileFragment(getActivity(), xxyDataB,handler,false);
Fragment xxyFragmentC = new SmileFragment(getActivity(), xxyDataC,handler,false);
Fragment xxyFragmentD = new SmileFragment(getActivity(), xxyDataD,handler,false);
Fragment xxyFragmentE = new SmileFragment(getActivity(), xxyDataE,handler,false);
//ltFragment
Fragment ltFragmentA = new SmileFragment(getActivity(), ltDataA,handler,false);
Fragment ltFragmentB = new SmileFragment(getActivity(), ltDataB,handler,false);
Fragment ltFragmentC = new SmileFragment(getActivity(), ltDataC,handler,false);
emojiFragmentData.add(emojiFragmentA);
emojiFragmentData.add(emojiFragmentB);
emojiFragmentData.add(emojiFragmentC);
emojiFragmentData.add(emojiFragmentD);
emojiFragmentData.add(emojiFragmentE);
emojiFragmentData.add(ajmdFragmentA);
emojiFragmentData.add(ajmdFragmentB);
emojiFragmentData.add(ajmdFragmentC);
emojiFragmentData.add(ajmdFragmentD);
emojiFragmentData.add(ajmdFragmentE);
emojiFragmentData.add(ajmdFragmentF);
emojiFragmentData.add(xxyFragmentA);
emojiFragmentData.add(xxyFragmentB);
emojiFragmentData.add(xxyFragmentC);
emojiFragmentData.add(xxyFragmentD);
emojiFragmentData.add(xxyFragmentE);
emojiFragmentData.add(ltFragmentA);
emojiFragmentData.add(ltFragmentB);
emojiFragmentData.add(ltFragmentC);
}
/**
* 初始化Fragment数据
*/
private void initFragmentData()
{
//emoji的数据赋值
emojidata = Const.smileData.get(0);
Log.i("Smile", "emojidata数量:"+emojidata.size());
emojiDataA= new ArrayList<Bitmap>(emojidata.subList(0, 27));
emojiDataB = new ArrayList<Bitmap>(emojidata.subList(27, 54));
emojiDataC = new ArrayList<Bitmap>(emojidata.subList(54,81));
emojiDataD = new ArrayList<Bitmap>(emojidata.subList(81,108));
emojiDataE = new ArrayList<Bitmap>(emojidata.subList(108, emojidata.size()));
//ajmd的数据赋值
ajmddata = Const.smileData.get(1);
ajmdDataA= new ArrayList<Bitmap>(ajmddata.subList(0, 8));
ajmdDataB= new ArrayList<Bitmap>(ajmddata.subList(8, 16));
ajmdDataC= new ArrayList<Bitmap>(ajmddata.subList(16, 24));
ajmdDataD= new ArrayList<Bitmap>(ajmddata.subList(24, 32));
ajmdDataE= new ArrayList<Bitmap>(ajmddata.subList(32, 40));
ajmdDataF = new ArrayList<Bitmap>(ajmddata.subList(40, ajmddata.size()));
//xxl的数据赋值
xxydata = Const.smileData.get(2);
xxyDataA= new ArrayList<Bitmap>(xxydata.subList(0, 8));
xxyDataB= new ArrayList<Bitmap>(xxydata.subList(8, 16));
xxyDataC= new ArrayList<Bitmap>(xxydata.subList(16, 24));
xxyDataD= new ArrayList<Bitmap>(xxydata.subList(24, 32));
xxyDataE = new ArrayList<Bitmap>(xxydata.subList(32, xxydata.size()));
ltdata = Const.smileData.get(3);
ltDataA= new ArrayList<Bitmap>(ltdata.subList(0, 8));
ltDataB = new ArrayList<Bitmap>(ltdata.subList(8, 16));
ltDataC = new ArrayList<Bitmap>(ltdata.subList(16,ltdata.size()));
}
/**
* 控件初始化
*/
private void initView()
{
main = (LinearLayout) layout.findViewById(R.id.chart_emoji);
viewPager = (ViewPager) layout.findViewById(R.id.chart_emoji_Viewpager);
indicatorButton1 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator1);
indicatorButton2 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator2);
indicatorButton3 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator3);
indicatorButton4 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator4);
indicatorButton5 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator5);
indicatorButton6 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator6);
indicatorButton7 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator7);
indicatorButton8 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator8);
indicatorButton9 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator9);
indicatorButton10 = (ImageButton) layout.findViewById(R.id.emoji_pager_indicator10);
smile_emoji = (ImageView) layout.findViewById(R.id.emoji_eump_A);
smile_ajmd = (ImageView) layout.findViewById(R.id.emoji_eump_B);
smile_xxy = (ImageView) layout.findViewById(R.id.emoji_eump_C);
smile_lt = (ImageView) layout.findViewById(R.id.emoji_eump_D);
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
setEnumValue();
initListener();
type = smileType.SMILE_TYPE_EMOJI;
initPagerIndicator(enumemoji);
smile_emoji.setSelected(true);
indicatorButton1.setSelected(true);
Log.i("Smile", "onActivityCreated=========```````````````````");
super.onActivityCreated(savedInstanceState);
}
/**
* 初始化页码指示器
* @param Volume 需要显示的页码数量
*/
private void initPagerIndicator(int Volume)
{
//初始化的页码指示器为10个
int toalt = 10;
Volume = toalt-Volume;
indicatorButton10.setVisibility(View.VISIBLE);
indicatorButton9.setVisibility(View.VISIBLE);
indicatorButton8.setVisibility(View.VISIBLE);
indicatorButton7.setVisibility(View.VISIBLE);
indicatorButton6.setVisibility(View.VISIBLE);
indicatorButton5.setVisibility(View.VISIBLE);
indicatorButton4.setVisibility(View.VISIBLE);
indicatorButton3.setVisibility(View.VISIBLE);
indicatorButton10.setSelected(false);
indicatorButton9.setSelected(false);
indicatorButton8.setSelected(false);
indicatorButton7.setSelected(false);
indicatorButton6.setSelected(false);
indicatorButton5.setSelected(false);
indicatorButton4.setSelected(false);
indicatorButton3.setSelected(false);
indicatorButton2.setSelected(false);
indicatorButton1.setSelected(false);
switch ((Volume)) {
case 1:
indicatorButton10.setVisibility(View.GONE);
break;
case 2:
indicatorButton10.setVisibility(View.GONE);
indicatorButton9.setVisibility(View.GONE);
break;
case 3:
indicatorButton10.setVisibility(View.GONE);
indicatorButton9.setVisibility(View.GONE);
indicatorButton8.setVisibility(View.GONE);
break;
case 4:
indicatorButton10.setVisibility(View.GONE);
indicatorButton9.setVisibility(View.GONE);
indicatorButton8.setVisibility(View.GONE);
indicatorButton7.setVisibility(View.GONE);
break;
case 5:
indicatorButton10.setVisibility(View.GONE);
indicatorButton9.setVisibility(View.GONE);
indicatorButton8.setVisibility(View.GONE);
indicatorButton7.setVisibility(View.GONE);
indicatorButton6.setVisibility(View.GONE);
break;
case 6:
indicatorButton10.setVisibility(View.GONE);
indicatorButton9.setVisibility(View.GONE);
indicatorButton8.setVisibility(View.GONE);
indicatorButton7.setVisibility(View.GONE);
indicatorButton6.setVisibility(View.GONE);
indicatorButton5.setVisibility(View.GONE);
break;
case 7:
indicatorButton10.setVisibility(View.GONE);
indicatorButton9.setVisibility(View.GONE);
indicatorButton8.setVisibility(View.GONE);
indicatorButton7.setVisibility(View.GONE);
indicatorButton6.setVisibility(View.GONE);
indicatorButton5.setVisibility(View.GONE);
indicatorButton4.setVisibility(View.GONE);
break;
case 8:
indicatorButton10.setVisibility(View.GONE);
indicatorButton9.setVisibility(View.GONE);
indicatorButton8.setVisibility(View.GONE);
indicatorButton7.setVisibility(View.GONE);
indicatorButton6.setVisibility(View.GONE);
indicatorButton5.setVisibility(View.GONE);
indicatorButton4.setVisibility(View.GONE);
indicatorButton3.setVisibility(View.GONE);
break;
case 9:
//剩下最后一页也没有必要用页码指示器了
}
}
/*
* 自定义枚举范围
*/
private void setEnumValue() {
Log.i("Smile", "emojidata---->"+emojidata.size());
enumemoji = getIntFromList(emojidata, 27);//5
enumajmd = getIntFromList(ajmddata, 8);//6
enumxxy = getIntFromList(xxydata, 8);//5
enumlt = getIntFromList(ltdata, 8);//3
enumEomjiVolume = enumemoji-1;//4
enumAjmdVolume = enumEomjiVolume+enumajmd;//10
enumXxyVolume = enumAjmdVolume+enumxxy;//15
enumLtVolume = enumXxyVolume+enumlt;//18
}
private void initListener()
{
viewPager.setOnPageChangeListener(new OnPageChangeListener()
{
/**
* ViewPager选中的状态
* 根据当前的页码来判断
* 0~4 smileType.SMILE_TYPE_EMOJI;
* 5~10 smileType.SMILE_TYPE_AJMD;
* 11~15 smileType.SMILE_TYPE_XXY;
* 16~18 smileType.SMILE_TYPE_LT;
*
*/
@Override
public void onPageSelected(int position)
{
//<=4
if(position<=enumEomjiVolume)
type = smileType.SMILE_TYPE_EMOJI;
//4>&&<=10
if(position>enumEomjiVolume && position<=enumAjmdVolume)
type = smileType.SMILE_TYPE_AJMD;
//10>&&<=15
if(position>enumAjmdVolume && position<=enumXxyVolume)
type = smileType.SMILE_TYPE_XXY;
//15>&&<=18
if(position>enumXxyVolume && position<=enumLtVolume)
type = smileType.SMILE_TYPE_LT;
checkType(position,(compareType==type),currentIndexPager);
currentIndexPager =position;
compareType = type;
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2)
{
}
@Override
public void onPageScrollStateChanged(int arg0)
{
}
});
smile_emoji.setOnClickListener(this);
smile_ajmd.setOnClickListener(this);
smile_xxy.setOnClickListener(this);
smile_lt.setOnClickListener(this);
}
/**
* 检查当前状态并定义在不同状态下需要完成的任务
* @param current 当前页码
* @param isChangeType 当前状态较上一次状态是否有改变
* @param last 上一页码
* 先根据当前的状态,计算需要显示的当前页码位置CurrentIndex以及需要关闭的上一个页码位置LastIndex
* 然后判断当前的状态是否发生改变?
* 是: 1、将页码指示器全部按照每个状态的区间宽度显示相应数量的页码器,并将之前的状态清零
* 2、然后将当前的页码器位置以及上一个位置不需要修改的参数传给changeIndicatorButton方法
* 否:直接将上一个页码器的位置以及当前页码器的位置传给changeIndicatorButton
*/
private void checkType(int current,boolean noChangeType,int last)
{
int LastIndex = 1;
int CurrentIndex = 0;
switch (type)
{
case SMILE_TYPE_EMOJI:
CurrentIndex = current+1;
LastIndex = last+1;
break;
case SMILE_TYPE_AJMD:
CurrentIndex = current+1-enumEomjiVolume;
LastIndex = last+1-enumEomjiVolume;
break;
case SMILE_TYPE_XXY:
CurrentIndex = current+1-enumAjmdVolume;
LastIndex = last+1-enumAjmdVolume;
break;
case SMILE_TYPE_LT:
CurrentIndex = current+1-enumXxyVolume;
LastIndex = last+1-enumXxyVolume;
break;
}
if(!noChangeType)
{
switch (type)
{
case SMILE_TYPE_EMOJI:
initPagerIndicator(enumemoji);
stateChangedWork(SMILE_TYPE_EMOJI);
break;
case SMILE_TYPE_AJMD:
initPagerIndicator(enumajmd);
stateChangedWork(SMILE_TYPE_AJMD);
break;
case SMILE_TYPE_XXY:
initPagerIndicator(enumxxy);
stateChangedWork(SMILE_TYPE_XXY);
break;
case SMILE_TYPE_LT:
initPagerIndicator(enumlt);
stateChangedWork(SMILE_TYPE_LT);
break;
}
changeIndicatorButton(CurrentIndex,100);
}else
{
changeIndicatorButton(CurrentIndex,LastIndex);
}
}
/**
* 根据参数,执行状态显示
* 1、得到当前的位置的current,然后判断current的值,然后对相应的选择器设为选中状态;
* 2、接下来得到上一个位置的last,然后判断last的值,
* 如果等于100,则意味着不需要对上一个位置的选择器状态进行修改,直接返回退出该方法
* 否则就对上一个位置的选择器状态设置为未选中。
* @param current 当前页码 需要改为选中状态
* @param last 上一页码 需要改为未选中状态
*
*/
private void changeIndicatorButton(int current,int last)
{
Log.i("Smile","changeIndicatorButton:"+"current->"+current+",last->"+last);
switch (current)
{
case 6:
indicatorButton6.setSelected(true);
break;
case 5:
indicatorButton5.setSelected(true);
break;
case 4:
indicatorButton4.setSelected(true);
break;
case 3:
indicatorButton3.setSelected(true);
break;
case 2:
indicatorButton2.setSelected(true);
break;
case 1:
indicatorButton1.setSelected(true);
break;
}
if(last==100)
return;
switch (last)
{
case 6:
indicatorButton6.setSelected(false);
break;
case 5:
indicatorButton5.setSelected(false);
break;
case 4:
indicatorButton4.setSelected(false);
break;
case 3:
indicatorButton3.setSelected(false);
break;
case 2:
indicatorButton2.setSelected(false);
break;
case 1:
indicatorButton1.setSelected(false);
break;
}
}
/**
* 通过集合获取自定义的数字
* 这里获取盛放数据的ViewPager需要多少pager
* @param data
* @return
* 注意:获取到的数字是从一开始计数,ViewPager里面是从0开始计算位置所以得到的数字减一
*/
private int getIntFromList(List<Bitmap> data,int volume)
{
float volumeF = volume*1.0f;
double pagers = data.size()/volumeF;
return (int) Math.ceil(pagers);
}
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.emoji_eump_A:
stateChangedWork(SMILE_TYPE_EMOJI);
break;
case R.id.emoji_eump_B:
stateChangedWork(SMILE_TYPE_AJMD);
break;
case R.id.emoji_eump_C:
stateChangedWork(SMILE_TYPE_XXY);
break;
case R.id.emoji_eump_D:
stateChangedWork(SMILE_TYPE_LT);
break;
}
}
/**
* 选择了不同的Imageview,状态栏的Imageview工作内容
* @param index
*/
private void stateChangedWork(int index)
{
switch (index)
{
case SMILE_TYPE_EMOJI:
viewPager.setCurrentItem(0);
// smile_emoji.setEnabled(true);
// smile_ajmd.setEnabled(false);
// smile_xxy.setEnabled(false);
// smile_lt.setEnabled(false);
smile_emoji.setSelected(true);
smile_ajmd.setSelected(false);
smile_xxy.setSelected(false);
smile_lt.setSelected(false);
break;
case SMILE_TYPE_AJMD:
viewPager.setCurrentItem(enumEomjiVolume+1);
// smile_emoji.setEnabled(false);
// smile_ajmd.setEnabled(true);
// smile_xxy.setEnabled(false);
// smile_lt.setEnabled(false);
smile_emoji.setSelected(false);
smile_ajmd.setSelected(true);
smile_xxy.setSelected(false);
smile_lt.setSelected(false);
break;
case SMILE_TYPE_XXY:
viewPager.setCurrentItem(enumAjmdVolume+1);
// smile_emoji.setEnabled(false);
// smile_ajmd.setEnabled(false);
// smile_xxy.setEnabled(true);
// smile_lt.setEnabled(false);
smile_emoji.setSelected(false);
smile_ajmd.setSelected(false);
smile_xxy.setSelected(true);
smile_lt.setSelected(false);
break;
case SMILE_TYPE_LT:
viewPager.setCurrentItem(enumXxyVolume+1);
// smile_emoji.setEnabled(false);
// smile_ajmd.setEnabled(false);
// smile_xxy.setEnabled(false);
// smile_lt.setEnabled(true);
smile_emoji.setSelected(false);
smile_ajmd.setSelected(false);
smile_xxy.setSelected(false);
smile_lt.setSelected(true);
break;}
}
/**
* 设置ViewPager的自适应
* @param childViewHeight
*/
private void setViewPagerWrapContentHeight(int childViewHeight)
{
int viewPagerIndex = main.indexOfChild(viewPager);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, childViewHeight );//这里设置params的高度。
main.removeView(viewPager);
main.addView(viewPager, viewPagerIndex , params);//使用这个params
}
}
整个篇幅还是比较臃肿,有700多行代码,ChartSmileFragment是本文的重点,所以我们先从onCreateView方法进行分析:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
layout = inflater.inflate(R.layout.chart_emoji, container,false);
initView();
initFragmentData();
initFragment();
initViewPager();
return layout;
}
这里首先获得布局的View,然后调用了4个方法,分别是初始化控件、初始化Fragment需要的数据、初始化Fragment、初始化ViewPager。这里着重讲Fragment数据的初始化以及Fragment的初始化。
Fragment的数据初始化就是直接从我们获取的emoji类型的Bitmap集合里复制相应的长度作为数据,这里为什么没有使用更简单的截取呢?因为我们在Fragment内需要对emoji类型的表情统一的在末尾添加一张删除的图片,如果这里直接截取的话,后面添加的时候会触发java.util.ConcurrentModificationException,所以我们这里是这样复制的:
//emoji的数据赋值
emojidata = Const.smileData.get(0);
Log.i("Smile", "emojidata数量:"+emojidata.size());
emojiDataA= new ArrayList<Bitmap>(emojidata.subList(0, 27));
emojiDataB = new ArrayList<Bitmap>(emojidata.subList(27, 54));
emojiDataC = new ArrayList<Bitmap>(emojidata.subList(54,81));
emojiDataD = new ArrayList<Bitmap>(emojidata.subList(81,108));
emojiDataE = new ArrayList<Bitmap>(emojidata.subList(108, emojidata.size()));
接下来,我们看看Fragment初始化的时候有什么值得关注的?先看部分
//emojiFragment
Fragment emojiFragmentA = new SmileFragment(getActivity(), emojiDataA,handler,true);
Fragment emojiFragmentB = new SmileFragment(getActivity(), emojiDataB,handler,true);
Fragment emojiFragmentC = new SmileFragment(getActivity(), emojiDataC,handler,true);
Fragment emojiFragmentD = new SmileFragment(getActivity(), emojiDataD,handler,true);
Fragment emojiFragmentE = new SmileFragment(getActivity(), emojiDataE,handler,true);
这些参数不明白是什么一样没有关系,马上到SmileFragment的构造方法看一下:
/**
*
* @param context 上下文对象
* @param Data GridView需要的数据
* @param handler 用来传回子View高度给Activity的ViewPager
* @param isIcon 判断是不是标准的emoji表情,如果不是的话,需要加载不同的布局,
*/
public SmileFragment(Context context,List<Bitmap> Data,Handler handler,boolean isIcon)
{
this.context = context;
bitmapData = Data;
this.handler = handler;
this.isIcon = isIcon;
if(isIcon)
bitmapData.add(BitmapFactory.decodeResource(this.context.getResources(), R.drawable.nim_emoji_del));
}
这里我们查看一下我们传的这些参数的意义以及作用:
contex,这个参数是作为习惯传过来,以备后面有需要的地方;
Data,Fragment里面的GridView需要的具体数据;
handler,主要的作用是传递第一个Gridview的高度以及GridView点击图片的位置;
isIcon,主要的作用是判断是不是emoji类型的Fragment,如果是的话,需要加载不同的xml文件,且需要对数据增加一个删除的图片,因为这个参数使得我们19个Fragment可以使用一个Fragment类。
OK,接着我们对ChartSmileFragment类继续探索,接着我们进入到onActivityCreated方法查看一番:
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
setEnumValue();
initListener();
type = smileType.SMILE_TYPE_EMOJI;
initPagerIndicator(enumemoji);
smile_emoji.setSelected(true);
indicatorButton1.setSelected(true);
super.onActivityCreated(savedInstanceState);
}
这里几个方法见简单的介绍一下:
setEnumValue()主要是对效果图最下面的四个类型的表情类型选择器进行分地盘,ViewPager显示每个不同的类型,这时候线程中就会是不同的状态。待会重点关注;
initListener()主要是对ViewPager的监听以及下面的四个表情类型选择器的监听;
type = smileType.SMILE_TYPE_EMOJI默认状态为emoji;
initPagerIndicator(enumemoji)这个方法主要是设置ViewPager页码指示器显示出来的数量,这里默认是emoji需要的数量;
smile_emoji.setSelected(true);这一句表示emoji这个表情类型选择器默认被选中;
indicatorButton1.setSelected(true);这一句表示显示出来的ViewPager页码指示器第一个默认被选中;
我们重点查看分地盘以及ViewPager的监听;首先看看分地盘的活动是怎么分的?
/*
* 自定义枚举范围
*/
private void setEnumValue() {
enumemoji = getIntFromList(emojidata, 27);//5
enumajmd = getIntFromList(ajmddata, 8);//6
enumxxy = getIntFromList(xxydata, 8);//5
enumlt = getIntFromList(ltdata, 8);//3
enumEomjiVolume = enumemoji-1;//4
enumAjmdVolume = enumEomjiVolume+enumajmd;//10
enumXxyVolume = enumAjmdVolume+enumxxy;//15
enumLtVolume = enumXxyVolume+enumlt;//18
}
这里是先对每一个类型的表情图片总数拿到后计算出每个类型的表情需要显示几个Fragment,然后计算ViewPager的item区间即每个状态的活动空间;
接着我们查看ViewPager的监听:
viewPager.setOnPageChangeListener(new OnPageChangeListener()
{
/**
* ViewPager选中的状态
* 根据当前的页码来判断
* 0~4 smileType.SMILE_TYPE_EMOJI;
* 5~10 smileType.SMILE_TYPE_AJMD;
* 11~15 smileType.SMILE_TYPE_XXY;
* 16~18 smileType.SMILE_TYPE_LT;
*
*/
@Override
public void onPageSelected(int position)
{
//<=4
if(position<=enumEomjiVolume)
type = smileType.SMILE_TYPE_EMOJI;
//4>&&<=10
if(position>enumEomjiVolume && position<=enumAjmdVolume)
type = smileType.SMILE_TYPE_AJMD;
//10>&&<=15
if(position>enumAjmdVolume && position<=enumXxyVolume)
type = smileType.SMILE_TYPE_XXY;
//15>&&<=18
if(position>enumXxyVolume && position<=enumLtVolume)
type = smileType.SMILE_TYPE_LT;
checkType(position,(compareType==type),currentIndexPager);
currentIndexPager =position;
compareType = type;
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2)
{
}
@Override
public void onPageScrollStateChanged(int arg0)
{
}
});
这里我们只是对onPageSelected方法进行了重写,根据上面的setEnumValue分地盘活动计算出来的活动空间,判断当前是哪一个表情类型在当家(ChartSmileFragment是哪一个状态),然后根据当前ViewPager的item和上一个item以及现在的状态与上一个状态是否改变来对界面进行一些设置。
这样基本上就完成了界面的显示,最后我们来看看当GridView被点击时,这个数据怎么传递到Activity,并且这些图片的传递过程我们进行了什么样的处理?
SmileFragment得到Gridview被点击的信息后,给上一层Fragment发送消息,并且将当前被点击的位置参数发过去:
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Message msg = new Message();
msg.what = 250;
msg.arg1 = position;
handler.handleMessage(msg);
}
当ChartSmileFragment收到消息后将被点击的位置参数交给了发送表情的方法来处理,我们看看这个方法:
private Handler handler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
if(msg.what==250)
{
Log.i("Smile", "收到发送表情信号");
sendSmile(msg.arg1);
}else
{
ViewPagerheightCount++;
if(ViewPagerheightCount==1)//ViewPager内第一个Fragment的高度
{
//将这个高度设为ViewPager的高度
setViewPagerWrapContentHeight(msg.what);
}
}
}
/**
* 发送表情图片
*/
private void sendSmile(int index)
{
if(type==smileType.SMILE_TYPE_EMOJI)
{//只需要直接显示在edittext
Smile smile = null;
boolean del = false;
switch (viewPager.getCurrentItem()) {
case 0:
//首先得到当前用户点击的表情的信息
Log.i("tag", "index----->"+index+"emojiDataA"+emojiDataA.size());
smile = Const.smiles.get(index);
if(index+1==emojiDataA.size())
{
del = false;
smile = null;
}
break;
case 1:
Log.i("tag", "index----->"+index+"emojiDataB"+emojiDataB.size());
smile = Const.smiles.get(27+index);
if(index+1==emojiDataB.size())
{
del = true;
smile = null;
}
break;
case 2:
Log.i("tag", "index----->"+index+"emojiDataC"+emojiDataC.size());
smile = Const.smiles.get(54+index);
if(index+1==emojiDataC.size())
{
del = true;
smile = null;
}
break;
case 3:
Log.i("tag", "index----->"+index+"emojiDataD"+emojiDataD.size());
smile = Const.smiles.get(81+index);
if(index+1==emojiDataD.size())
{
del = true;
smile = null;
}
break;
case 4:
Log.i("tag", "index----->"+index+"emojiDataE"+emojiDataE.size());
if(index+1==emojiDataE.size())
{
del = true;
smile = null;
}else
{
smile = Const.smiles.get(108+index);
}
break;
}
listener.chartSmileFragmnetToActivity(del,smile);
}else
{
switch (type) {
case SMILE_TYPE_AJMD :
break;
case SMILE_TYPE_XXY :
break;
case SMILE_TYPE_LT :
break;
default:
break;
}
}
};
发送表情图片的方法比较长,首先是判断当前状态,因为emoji状态的话表情图片是直接显示,然后以文本的方式发送,而其他状态则将表情图片直接发送并显示出来。所以我们直接看状态为smileType.SMILE_TYPE_EMOJI的时候怎么执行的?首先,它根据ViewPager在不同的页码来获取到不同Fragment的数据Data,并以此为根据得到表情图片的信息Smile对象,然后判断如果这个表情是当前SmileFragment最后一项的话,则是删除的图片,这个图片没有被封装,所以获取到的Smile参数是不正确的,这里设为null,并且设置Boolean型的参数del为true,最后将这两个座位参数传给接口的抽象方法,待Activity来实现它。这里的参数其实有一个Smile对象就可以搞定,大家试着继续优化吧!
重点提醒emoji状态的最后一页SmileFragment不能先获取Smile,因为如果GridView传过来的是删除图片的话,获取Smile的方法就会造成数组越界,所以最后的方法是先判断是不是删除的图片,不是的话再获取Smile对象。
最后到Activity里面看看这里实现接口的时候怎么处理的吧?
//点击emoji表情监听事件
SmileView.setOnSendEmojiIconListener(new OnSendEmojiIconListener()
{
@Override
public void chartSmileFragmnetToActivity(boolean isdelete,
Smile smile)
{
int end = etn_Context.getSelectionStart();
if(smile!=null)//不是删除,图片放到edittext上面
{
String path = "emoji/default/"+smile.getFile();
SpannableString ss = new SpannableString(path);
Bitmap bmp = Utils.getBitmapFromAssetsFile(mContext, path);
ImageSpan span = new ImageSpan(mContext,bmp );
ss.setSpan(span, 0, path.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Editable et = etn_Context.getText();// 先获取Edittext中的内容
et.insert(end, ss);// 设置ss要添加的位置
etn_Context.setText(et);// 把et添加到Edittext中
etn_Context.setSelection(end + ss.length());// 设置Edittext中光标在最后面显示
}else //删除上一个图片或者文字
{
if (end > 0) {
String body = etn_Context.getText().toString();
Log.i("tag", "body:"+body+"长度:"+body.toCharArray().length );
if (!TextUtils.isEmpty(body)) {
String tempStr = body.substring(0, end);
int i = tempStr.lastIndexOf(".png");
if (i != -1) {
CharSequence cs = tempStr
.subSequence(end-26, end-6);
if (cs.equals("emoji/default/emoji_")) {// 判断是否是一个表情
etn_Context.getEditableText().delete(tempStr.length() - 26, end);
return;
}}
etn_Context.getEditableText().delete(tempStr.length() - 1,
end);
}
}
}
}
});
这一步花了我两天时间,因为不会,所以才难。接口这里首先根据EditText控件的末尾光标信息,来判断当前需要添加图片或者删除图片的位置,接着根据Smile对象是否为空来判断当前是删除图片还是加载图片?
这里EditText控件加载图片主要涉及到了一个SpannableString类对文本进行了一些复合编辑,得到复合文本,然后获取EditText控件中的内容,接着在末尾的光标处插入文本,得当一个新的Editable对象,最后将这个Editable对象设为EditText控件的内容并将光标移至EditText控件的末尾处;
删除的时候就是获取当前的控件内容,然后判断是不是以“.png”结尾的,如果是的话,继续判断前面的字段是不是表情图片的路径,是的话就在末尾处删除一个表情的长度26,否则的话就在末尾删除一个字节的长度1.
最后,我们就这样的完成了表情图片的加载显示与点击表情插入EditText控件。最后说个文本内容监听,因为微信的输入框有内容时我们的编辑栏右边显示的是文本,没有内容时编辑栏右边显示的是图片。这个文本内容监听本来我打算用来删除图标和文本的时候用,谁知道走了弯路,后来继续研究的时候发现还好,还是有用。废话不多,瞧代码:
//edittext的内容变化监听事件
etn_Context.addTextChangedListener(OnContextChangeListener);
private TextWatcher OnContextChangeListener = new TextWatcher()
{
@Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after)
{
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s)
{
if(s.length()!=0)
{//EditText没有内容
btnSendMessage.setVisibility(View.VISIBLE);
ivAddContext.setVisibility(View.GONE);
}else
{//EditText还有内容
ivAddContext.setVisibility(View.VISIBLE);
btnSendMessage.setVisibility(View.GONE);
}
}
};
OK,本文大致就是如此了,请各位多多斧正!
ps:因为在后来的开发中又遇到一个坑,原来是埋在这里的,所以我就在这里单独说几句,把坑填了!
最近在写聊天记录的时候,我发现EditText里面的文本发送出去之后还是文本,根本就没有把里面的表情显示出来。一言不合就上图:
后来再次遍访(求)高人,终于找到了问题根节。根节点待会聊,这里先上代码对处理添加图片和删除图片以及文本的办法做一个优化,代码如下:
EmojiConversionUtils.INSTANCE.doFaceBusiness(mContext, smile, etn_Context);
优化后不是只用写一句代码就完成了,而是我们对这里进行了封装,这里自定义一个枚举类作为表情处理的工具类,然后在类里面封了这个方法,一言不合上代码:
public enum EmojiConversionUtils
{
INSTANCE;
/**
* 处理表情的添加或者删除表情及文字
*
* @param context
* @param imgId
* @param spannableString
* @return
*
*
*/
public void doFaceBusiness(Context context, Smile smile,EditText editText)
{
if(smile!=null)//不是删除,图片放到edittext上面
{
String path = "emoji/default/"+smile.getFile();
Bitmap bitmap = Utils.getBitmapFromAssetsFile(context, path);
ImageSpan imageSpan = new ImageSpan(context, bitmap);
SpannableString spannable = new SpannableString(smile.getTag());
spannable.setSpan(imageSpan, 0, smile.getTag().length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
editText.append(spannable);
}
else //删除上一个图片或者文字
{
int end = editText.getSelectionStart();
String text = editText.getText().toString();
if (end > 0) {
String text2 = text.substring(end - 1);
if ("]".equals(text2)) {
int start = text.lastIndexOf("[");
// int end = selection;
editText.getText().delete(start, end);
return;
}
editText.getText().delete(end - 1, end);
}
}
}
}
原来我之前对SpannableString这个类存在误解,他的构造方法public SpannableString (CharSequence source) 需要的参数不是指一定是图片的路径才可以,这里可以设为任意内容都可以。我们之前传入路径,现在传入tag,这里有几个好处:
1、数据更小,以前是最少26个字节,现在最多6个字节,最少4个字节,所以理论上来讲,传输时节约流量,效率更高;
2、对于后面处理TextView上面加载表情的时候也有帮助。
刚刚上面讲到对后面有帮助,那么我来理一理它是怎么帮助我的,这里我之前有一个误区,我理解的是我把图片转换为复合文本了,那么传输出去以后他也应该还是复合文本,但是事实上它传输出去之后还是普通文本,如效果图显示一样。这里我们需要将含有复合文本部分给挑出来并且转化为复合文本,但是这应该怎么实现呢?我之前的思路是对文本进行遍历来寻找表情文本String,找到之后转换为复合文本SpannableString,替换掉之后继续寻找,但是SpannableString是继承自CharSequence,所以我遍历第二次的时候始终跳不过第一次,于是我就开始遍寻(求)高人,终于让我看到了希望,不用自己遍历,通过正则表达式来寻找。一言不合又上代码:
//解析最后一个方法处,增加一行代码
//每次在结束解析一个元素,即遇到元素标签结束的时候都会调用。
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException
{
if(smile!=null)
{
if(smile.getFile()!=null)
{
smiles.add(smile);
//这里将标签和文件名称关联起来并保存,后面正则表达式处需要用到EmojiConversionUtils.INSTANCE.emojiMap.put(smile.getTag(),smile.getFile());
}
}
Log.i("Smile", "smiles:"+smiles.size());
smile = null;
}
package com.example.addsmile.utils;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.example.addsmile.entity.Smile;
import android.content.Context;
import android.graphics.Bitmap;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.util.Log;
import android.widget.EditText;
public enum EmojiConversionUtils
{
INSTANCE;
/**
* 保存于内存中的表情HashMap
*/
public HashMap<String, String> emojiMap = new HashMap<String, String>();
/**
* 处理表情的添加或者删除表情及文字
*
* @param context
* @param imgId
* @param spannableString
* @return
*
*
*/
public void doFaceBusiness(Context context, Smile smile,EditText editText)
{
if(smile!=null)//不是删除,图片放到edittext上面
{
String path = "emoji/default/"+smile.getFile();
Bitmap bitmap = Utils.getBitmapFromAssetsFile(context, path);
// bitmap = Bitmap.createScaledBitmap(bitmap, 50, 50, true);
ImageSpan imageSpan = new ImageSpan(context, bitmap);
SpannableString spannable = new SpannableString(smile.getTag());
spannable.setSpan(imageSpan, 0, smile.getTag().length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
editText.append(spannable);
}
else //删除上一个图片或者文字
{
int end = editText.getSelectionStart();
String text = editText.getText().toString();
if (end > 0) {
String text2 = text.substring(end - 1);
if ("]".equals(text2)) {
int start = text.lastIndexOf("[");
// int end = selection;
editText.getText().delete(start, end);
return;
}
editText.getText().delete(end - 1, end);
}
}
}
/**
* 得到一个SpanableString对象,通过传入的字符串,并进行正则判断
*
* @param context
* @param str
* @return
* 用法如下
SpannableString spannableString = EmojiConversionUtils.INSTANCE.getExpressionString(mContext,person.content);
viewHolder.content.setText(spannableString);
*/
public SpannableString getExpressionString(Context context, String str)
{
SpannableString spannableString = new SpannableString(str);
// 正则表达式比配字符串里是否含有表情,如: 我好[开心]啊
String zhengze = "\\[[^\\]]+\\]";
// 通过传入的正则表达式来生成一个pattern
Pattern sinaPatten = Pattern.compile(zhengze, Pattern.CASE_INSENSITIVE);
try
{
dealExpression(context, spannableString, sinaPatten, 0);
}
catch (Exception e)
{
Log.e("dealExpression", e.getMessage());
}
return spannableString;
}
/**
* 对spanableString进行正则判断,如果符合要求,则以表情图片代替
*
* @param context
* @param spannableString
* @param patten
* @param start
* @throws Exception
*/
private void dealExpression(Context context,
SpannableString spannableString, Pattern patten, int start)
throws Exception
{
Matcher matcher = patten.matcher(spannableString);
while (matcher.find())
{
// 返回第一个字符的索引的文本匹配整个正则表达式,ture 则继续递归
if (matcher.start() < start)
continue;
String key = matcher.group();
String value = emojiMap.get(key);
if (TextUtils.isEmpty(value)) continue;
String path = "emoji/default/"+value;
Bitmap bitmap = Utils.getBitmapFromAssetsFile(context, path);
@SuppressWarnings("deprecation")
ImageSpan imageSpan = new ImageSpan(bitmap);
// 计算该图片名字的长度,也就是要替换的字符串的长度
int end = matcher.start() + key.length();
// 将该图片替换字符串中规定的位置中
spannableString.setSpan(imageSpan, matcher.start(), end,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
if (end < spannableString.length())
{
// 如果整个字符串还未验证完,则继续。。
dealExpression(context, spannableString, patten, end);
}
break;
}
}
}
使用方法:
/**
* 解析表情
*/
SpannableString spannableString = EmojiConversionUtils.INSTANCE.getExpressionString(mContext,person.content);
viewHolder.content.setText(spannableString);
其实思路和我原来的思路一样,只是方法不一样。他是通过含有图片内容的普通文本转化为SpannableString对象,然后通过正则表达式对其进行遍历,拿到图片内容之后,只对这一部分进行替换,而不是全部替换,然后替换了之后比较替换时结束位置是不是SpannableString的结束位置,如果不是的话,就从替换时结束位置继续寻找图片文本,效果类似于递归,直至完成了(没有图片文本或者图片文本替换结束时位置和SpannableString的结束位置一致)就break退出了。
我之前属于一个人蛮干,这里是借助正则表达式来工作,一高一下一目了然!但是主要的是思维居然一致,我为自己点赞!
最后欢迎大家吐槽!!