屏幕適配
原型圖和設計圖
- 800*480 —> 向下兼容
- 1280*720 —> 向上兼容
圖片適配:
- 根據屏幕的分辨率,選擇drawable-xxxxx
- 圖片的名稱必須一致
佈局的適配:
- layout-xxx, xxxx 是 高x寬(大乘小)如:layout-480x320
- 佈局文件名稱一致
尺寸的適配:
- px: pexl 像素
- dip/dp: denisity-independent pexl 自主密度的像素
- ppi: pexl per inch 每英寸有多少個像素點 > 300
dpi: dots per inch 每英寸可打印的點
ppi的計算:
ppi = 開根(寬的平方 + 高的平方) / inch ppi = 開根(480^2 + 320^2) / 3.5 = 164
- dpi: 480*320 3.5 1dp = 1px dpi : 160
公式 : px = dp * (dpi / 160)
- dp = px / (dpi / 160);px自己想要的像素
- dpi值 ,自己查閱(文檔)
ldpi: 320x240
dp = 120 /(120/160) = 160dp
mdpi: 480x320
dp = 160 / ( 160 / 160) = 160dp
hdpi: 800x480
dp = 240 / (240/160) = 160dp
xhdpi: 1280x720
dp = 360 /(320/160) = 180dp
A set of six generalized densities:
ldpi (low) ~120dpi
mdpi (medium) ~160dpi
hdpi (high) ~240dpi
xhdpi (extra-high) ~320dpi
xxhdpi (extra-extra-high) ~480dpi
xxxhdpi (extra-extra-extra-high) ~640dpi
8. denisity : 像素密度(縮放比) denistity = px / dp;
1. dp = px / denistity;
通過代碼獲取手機相對應得像素,密度手機屏幕高度等相關信息:
DisplayMetris metrics=getResources().getDisplayMetrics();
float density=metrics.density;
float densityDpi=metrics.densityDpi;
- 代碼的適配(權重):
舉個例子:
//最外側的容器
LinearLayout container=new LinearLayout(this);
container.setOrientation(LinearLayout.VERTICAL);
LayoutParams params=new LayoutParams(LayoutParams.MATH_PARENT,LayoutParams.MATH_PARENT);
LinearLayout topLayout=new LinearLayout(this);
topLayout.setBackColor(Color.RED);
params.weight=1;
container.addView(topLayout,params);
LinearLayout buttomLayout=new LinearLayout(this);
buttomLayout.setBackColor(Color.RED);
params.weight=1;
container.addView(buttomLayout,params);
版本適配
- 通過判斷版本去寫代碼
- android.jar它是在手機環境中的,不是在apk中
例如:
AsyncTask<void,void,void> task=new AsyncTask<void,void,void>(){
protected void doInBackgroup(void...params){
return null;
}
};
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.HONEYCOMB){
//3.0之前是多線程的
task.execute();
}else{
//3.0之後是單線程隊列的
if(executor==null){//線程池不爲空,先定義出來
executor=Executors.newFixedThreadPool(3);//只開三個線程
}
//3.0之後是單線程隊列的
task.executeOnExecutor(executor);
}
科大訊飛語音
- 聽 :
- 說 :
- 搜索:科大訊飛語音雲
使用:
1. 註冊賬號
2. 創建應用
3. 使用服務
4. sdk下載
5. 集成
下面通過一個小案例來了解它的使用:語音機器人
通過科大訊飛文檔,先集成使用環境,抽出一個聽說的工具類
public class SpeekListenUtils
{
private Context mContext;
public SpeekListenUtils(Context context) {
this.mContext = context;
// 請勿在“=”與 appid 之間添加任務空字符或者轉義符
SpeechUtility.createUtility(context, SpeechConstant.APPID + "=57ab2dcc");//57ab2dcc爲自己應用申請的appkey
}
//聽的功能
public void listen(RecognizerDialogListener mRecognizerDialogListener)
{
// 1.創建RecognizerDialog對象
RecognizerDialog mDialog = new RecognizerDialog(mContext, null);
// 2.設置accent、language等參數
mDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
mDialog.setParameter(SpeechConstant.ACCENT, "mandarin");
// 若要將UI控件用於語義理解,必須添加以下參數設置,設置之後onResult回調返回將是語義理解 //結果 //
// mDialog.setParameter("asr_sch", "1"); //
// mDialog.setParameter("nlp_version", "2.0");
// 3.設置回調接口
mDialog.setListener(mRecognizerDialogListener);
// 4.顯示dialog,接收語音輸入
mDialog.show();
}
//說的功能
public void speak(String text,SynthesizerListener mSynthesizerListener)
{
// 1.創建SpeechSynthesizer 對象, 第二個參數:本地合成時傳InitListener
SpeechSynthesizer mTts= SpeechSynthesizer.createSynthesizer(mContext, null);
// //2.合成參數設置,詳見《MSC Reference Manual》SpeechSynthesizer 類
// //設置發音人(更多在線發音人,用戶可參見 附錄13.2
mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan"); //設置發音人
mTts.setParameter(SpeechConstant.SPEED, "50");//設置語速
mTts.setParameter(SpeechConstant.VOLUME, "80");//設置音量,範圍 0~100
mTts.setParameter(SpeechConstant.ENGINE_TYPE,
SpeechConstant.TYPE_CLOUD); //設置雲端
//設置合成音頻保存位置(可自定義保存位置),保存在“./sdcard/iflytek.pcm” //保存在 SD 卡需要在
// AndroidManifest.xml 添加寫 SD 卡權限 //僅支持保存爲 pcm 和 wav
// 格式,如果不需要保存合成音頻,註釋該行代碼
mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH,"./sdcard/iflytek.pcm");
//3.開始合成
mTts.startSpeaking(text, mSynthesizerListener);
}
}
現在先來看看語音機器人的實際效果圖:問時:
————-
機器答時:
———–
在集成的sdk環境中,在聽的時候會自動彈出一個透明對話框,這個已經封裝好了如上圖。我們自要對着屏幕說就可以啦。現在來看看:
先初始化佈局,這個佈局分爲一個按鈕,一個listView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.cca.speekrobot.MainActivity" >
<RelativeLayout
android:id="@+id/bottom_speak"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/bottom_bar"
>
<Button
android:id="@+id/btn_speak_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/btn_voice_search_normal"
android:textSize="25dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:gravity="center"
android:onClick="clickListen"
android:text="開始說話" />
</RelativeLayout>
<ListView
android:id="@+id/list_speak"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:cacheColorHint="@android:color/transparent"
android:fadingEdge="none"
android:layout_above="@id/bottom_speak"
android:dividerHeight="0dp"
android:listSelector="@android:color/transparent"
android:layout_height="match_parent">
</ListView>
</RelativeLayout>
初始化數據initData();
private void initData()
{
SpeekListenUtils utils=new SpeekListenUtils(this);
ListView mList=(ListView) findViewById(R.id.list_speak);
//設置數據
MyListAdapter adapter=new MyListAdapter();
mList.setAdapter(adapter);
}
給按鈕設置點擊事件
//點擊按鈕,開始說語音讓機器人聽
public void clickListen(View view){
utils.listen(new MyRecognizerDialogListener());
}
完成聽語音的監聽和數據的獲取:
private class MyRecognizerDialogListener implements RecognizerDialogListener{
@Override
public void onError(SpeechError arg0)
{
}
@Override
public void onResult(RecognizerResult arg0, boolean isLast)
{
String result=arg0.getResultString();
Log.i(TAG, "---"+result);
//解析json
Gson json=new Gson();
ListDataBean bean=json.fromJson(result, ListDataBean.class);
content += getResult(bean); //返回聽到的文字content初始化爲空字符串
//判斷是否是最後一次
if(isLast){
//最後一次、問的話content------>convert
ConvertBean ask=new ConvertBean();
ask.type=0;
ask.text=content;
if(mDatas==null){
mDatas=new LinkedList<ConvertBean>();
}
mDatas.add(ask);
//清空content
content="";
//UI刷新
adapter.notifyDataSetChanged();
//回答
String text=ask.text;
ConvertBean answer=null;
Random adm=new Random();
int textSize=RobotRes.resText.length;
int icomSize=RobotRes.resIcon.length;
if(text.contains("美女")){//這裏可以做很多判斷
//bean
answer =new ConvertBean();
answer.type=1;
answer.img=RobotRes.resIcon[adm.nextInt(icomSize)];//隨機返回
answer.text=RobotRes.resText[adm.nextInt(textSize)];//隨機返回
}else{
answer =new ConvertBean();
answer.type=1;
answer.img=-1;
answer.text="不好意思,沒聽懂,請再說一遍!";
}
//說出來
utils.speak(answer.text, null);
mDatas.add(answer);
//UI刷新
adapter.notifyDataSetChanged();
//滑動到下面可見
mList.setSelection(adapter.getCount());
}
}
}
//獲取數據
public String getResult(ListDataBean bean)
{
List<Wsbean> wsbean=bean.ws;
StringBuffer sb=new StringBuffer();
for(Wsbean ws:wsbean){
List<Cwbean> cwbean=ws.cw;
for(Cwbean cw:cwbean){
sb.append(cw.w);
}
}
return sb.toString();
}
給listView設置適配器:
//適配器
class MyListAdapter extends BaseAdapter{
@Override
public int getCount()
{
if(mDatas!=null){return mDatas.size();}
return 0;
}
@Override
public Object getItem(int position)
{
return mDatas.get(position);
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
//複用歷史的convertview
if(convertView==null){
convertView=View.inflate(getApplicationContext(), R.layout.list_item, null);
holder=new ViewHolder();
holder.mAskLinLayout=convertView.findViewById(R.id.ask_container);
holder.mAnswerRelLayout=convertView.findViewById(R.id.answer_container);
holder.asktext=(TextView) convertView.findViewById(R.id.ask_text);
holder.answertext=(TextView) convertView.findViewById(R.id.answer_text);
holder.answerimg=(ImageView) convertView.findViewById(R.id.answer_img);
convertView.setTag(holder);
}else{
holder=(ViewHolder) convertView.getTag();
}
//設置數據
ConvertBean data=mDatas.get(position);
if(data.type==0){
//問
holder.mAskLinLayout.setVisibility(View.VISIBLE);
holder.mAnswerRelLayout.setVisibility(View.GONE);
holder.asktext.setText(data.text);
}else{
//答
holder.mAskLinLayout.setVisibility(View.GONE);
holder.mAnswerRelLayout.setVisibility(View.VISIBLE);
holder.answertext.setText(data.text);
if(data.img!=-1){
holder.answerimg.setImageResource(data.img);
}
}
return convertView;
}
}
class ViewHolder{
View mAskLinLayout;
View mAnswerRelLayout;
TextView asktext;
TextView answertext;
ImageView answerimg;
}
在完成之前先創建問答在listView顯示的item佈局:
<?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:orientation="vertical" >
<!-- 問--- 右側 -->
<RelativeLayout
android:id="@+id/ask_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true" >
<TextView
android:id="@+id/ask_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="@drawable/asker_bubble"
android:textColor="#000000"
android:gravity="center"
android:text="sdfghjkdshdeSD卡萬能fghj" />
</RelativeLayout>
<!-- 答--- 左側 -->
<LinearLayout
android:id="@+id/answer_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:orientation="vertical" >
<TextView
android:id="@+id/answer_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/answer_bubble"
android:gravity="center"
android:textColor="#000000"
android:text="sdfghjkdshdeSD卡萬能fghj" />
<ImageView
android:id="@+id/answer_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/ic_launcher" />
</LinearLayout>
</LinearLayout>
下面是自己創建的資源文件,圖片放在drawable-hdpi中
public class RobotRes
{
public static int[] resIcon=new int[]{
R.drawable.p1,R.drawable.p2,
R.drawable.p3,R.drawable.p4,
R.drawable.p5,R.drawable.p6,
R.drawable.p7,R.drawable.p8,
R.drawable.p9,R.drawable.p10,
};
public static String[] resText=new String[]{
"專業辦證300年","天王蓋地虎",
"屌絲,朝前看吧","色狼,你的最愛",
"我愛你","看見你死而無憾了",
"世上有你相伴最好"
};
}
存儲數據的javabean:
public class ConvertBean
{
String text;
int img=-1;
int type=0;//0位問 ,1 爲答
}
把獲得的數據解析的javabean:
public class ListDataBean
{
public int bg;
public int ed;
public boolean ls;
public int sn;
public List<Wsbean> ws;
class Wsbean{
public int bg;
public List<Cwbean> cw;
}
class Cwbean{
public double sc;
public String w;
}
}
到這裏,語音機器人就簡單完成了,這裏只是簡單介紹了語音sdk的集成和使用,具體的還需要多多研究。