少废话,先看东西【还在编辑中…】
代码链接:点这里
APK链接::点这里
首先,纯小白起步,参考了很多代码,如有抄袭……我也没干嘛,分享下经验嘛…
侧滑相关参考:
toolbar相关参考:
https://blog.csdn.net/tideseng/article/details/52804277?locationNum=3
Toolbar、侧滑布局及其功能的实现
- 主界面(activity_main)
Toolbar(内嵌文字标题 ‘使用自己的标题不好居中’)+FrameLayout(点击侧滑菜单的选项即时更换FrameLayout内容)+DrawerLayout(实现侧滑,通过NavigationView添加上下两部分布局)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/AppTheme"
tools:context="com.example.big_god.text.MainActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新短信"
android:textSize="18sp"
android:textColor="#FFF"
android:layout_gravity="center"/>
</android.support.v7.widget.Toolbar>
<FrameLayout
android:id="@+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
<android.support.design.widget.NavigationView
android:id="@+id/nav"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:headerLayout="@layout/head"
app:menu="@menu/my_menu"
app:itemBackground="@color/white"
android:layout_gravity="start"
></android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
这里说明一下,Toolbar的图标自动变形想自己实现挺难…找好久才找到一个简单的方法,不用自己加图标。
//我这里声明的Toolbar 为toollbar,DrawerLayout为dl
setSupportActionBar(toolbar);
// 参数:开启抽屉的activity、DrawerLayout的对象、toolbar按钮打开关闭的对象、描述open drawer、描述close drawer
ActionBarDrawerToggle abdt = new ActionBarDrawerToggle(MainActivity.this, dl, toolbar,R.string.dl_open,R.string.dl_close){
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
//根据滑动百分比计算内容部分应该向右边移动的距离
int marginLeft = (int) (drawerView.getMeasuredWidth()* slideOffset);
//获得内容部分的View对象(内容View对象是第一个,所以是0)
LinearLayout contentView = (LinearLayout) dl.getChildAt(0);
//修改内容部分的左边距
contentView.setLeft(marginLeft);
}
};
// 添加抽屉按钮,通过点击按钮实现打开和关闭功能; 如果不想按钮有点急功能可以不写此行代码
adbt.syncState();
// 设置按钮的动画效果; 如果不想要打开关闭抽屉时的箭头动画效果,可以不写此行代码
dl.addDrawerListener(abdt);
另外设置侧栏滑出后去掉原界面的阴影需要用到这个方法
dl.setScrimColor(Color.TRANSPARENT); //dl为DrawerLayout的对象
Fragment的切换实现
首先,要明白我只有一个Activity,动态加载Fragment到FrameLayout,这就涉及Activity获取Fragment中控件以及动态加载Fragment,要实现Fragment中的功能就有两种方法:
1、Fragment每次加载完成时Activity获取对应Fragment的所有控件并初始化而且还要实现其事件(代码全在Activity中),我折腾了2天放弃了,要么能获取控件不能响应事件,要么程序直接崩,同时请教下这个问题;
2、Fragment控件及其功能在Fragment中完成,Activity只负责切换Fragmnet,不扯它的控件。
下面是切换Fragment的实现
//nv为NavigationView的对象
nv.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case (R.id.about_item):
//About_fragment()为对应Fragment的Java类,内容见下段
getFragmentManager().beginTransaction().replace(R.id.frame, new About_Fragment()).commit();
title.setText("关于");
break;
case (R.id.Turing_item):
getFragmentManager().beginTransaction().replace(R.id.frame, new Turing_Fragment()).commit();
title.setText("图灵机器人");
break;
case (R.id.direction_item):
getFragmentManager().beginTransaction().replace(R.id.frame, new Direction_Fragment()).commit();
title.setText("说明");
break;
default:
getFragmentManager().beginTransaction().replace(R.id.frame, new Text_Fragment()).commit();
title.setText("新短信");
break;
}
dl.closeDrawer(nv);
return true;
}
});
Fragment的Java代码
这里只举个最简单的例子看看。About_Fragment 中没有相关事件,不用对控件进行初始化,如果有控件,必须在onViewCreated()中初始化(切记)。
public class About_Fragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_about,container,false);
}
}
浏览器功能的实现
这里浏览器功能实现得很简陋,没有按钮什么的,只实现了返回键返回上一页面这个功能,首先跳转到我自己搭建的一个服务器页面,然后提供按钮跳转到百度,到了百度然后不就可以随便去了吗?
首先看浏览器布局代码
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"></WebView>
就一个Webview,再看它的实现,包括传说中的ERR_UNKNOWN_URL_SCHEME错误的解决方法。
//申请权限
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.INTERNET}, 1);
} else {
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);//支持js
webSettings.setDomStorageEnabled(true);//支持dom缓存
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String request) {
//关于那个错误,查了很久据说是Webview不认除http和https之外的链接导致的
//看见过一种“解决方法”就是在这个方法中判断协议不为http和https的直接丢给外部浏览器解析,但我想要的是在这个控件中完成所有操作。
//然后就发现这个方法只要返回true就调用外部浏览器,返回false则自己执行,于是...
//直接返回false就莫名其妙好了,,反正我的没问题
return false;
}
});
webView.loadUrl(url);
}
//返回键监听,实现页面后退功能,返回到最初的页面再按返回直接退出程序
webView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int i, KeyEvent keyEvent) {
if(keyEvent.getAction()==KeyEvent.ACTION_DOWN)
if(i==KeyEvent.KEYCODE_BACK&&webView.canGoBack()){
webView.goBack();
return true;
}
return false;
}
});
发短信
这个网上的教程很详细了,但我测试发现小米的机器发送不了,猜测应该是MIUI把Android魔改得太严重了……
如果想监听短信发送状态需要设置广播,这个……懒得做…
public void sendMsg(String phoneNumber, String message) {
//获取短信管理器
android.telephony.SmsManager smsManager = android.telephony.SmsManager.getDefault();
//拆分短信内容(手机短信长度限制)
List<String> divideContents = smsManager.divideMessage(message);
for (String text : divideContents) {
smsManager.sendTextMessage(phoneNumber, null, text, null, null);//小米的这一行报错
}
}
图灵机器人模块的实现
其实也很简单,HttpURLConnection发送个链接再解析并截取它返回的数据就可以了,纯文本,特别简单,就是要注意Android是不能在主线程中发送HTTP请求的,这时候就涉及到多线程,多线程就需要用到同步。
这个CommonException 是我自定义的异常类,我用的是JSON解析的返回值。
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class HttpData {
private static String API_KEY = "d8c6461d3956425e95b498534705554d";
private static String URL = "http://www.tuling123.com/openapi/api";
private StringBuilder sb;
/*
得到消息
*/
public Message sendMsg(String msg) throws CommonException {
Message message = new Message();
String url = setParams(msg);
String temp = Getdo(url);
if (sb.toString().equals(url)) {
return null;
}
message.setMsg(temp);
message.setFlag(Message.RECEIVED);
message.setTime(new SimpleDateFormat("MM月dd日 HH:mm:ss", Locale.getDefault()).format(new Date(System.currentTimeMillis())));
return message;
}
/*
* 拼接Url
*/
private String setParams(String msg) throws CommonException {
/** 利用Java中URLEncoder对其进行编码,如果不能实现,抛出异常 */
try {
msg = URLEncoder.encode(msg, "UTF-8");
} catch (Exception e) {
throw new CommonException("编码异常");
}
return URL + "?key=" + API_KEY + "&info=" + msg;
}
private String Getdo(String msg){
sb = new StringBuilder(msg);
try {
HttpURLConnection urlConnection = (HttpURLConnection) new URL(sb.toString()).openConnection();
urlConnection.setConnectTimeout(5 * 1000);
urlConnection.connect();
if (urlConnection.getResponseCode() == 200) {
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "utf-8"));
String line = "";
sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
urlConnection.disconnect();
} else {
throw new CommonException("连接超时");
}
JSONObject json = new JSONObject(sb.toString());
if (json.getInt("code") == 100000) {
sb = new StringBuilder(json.getString("text"));
} else {
throw new CommonException("提交格式出錯");
}
} catch (Exception e) {
}
return sb.toString();
}
}
线程的处理
try {
Thread thread = new Thread(){
@Override
public void run() {
try {
receive = httpData.sendMsg(msg.getText().toString());
} catch (CommonException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
};
thread.start();//启动线程
thread.join();//子线程加入主线程的进程,意思就是主线程等子线程跑完再继续
if(receive==null){
Toast.makeText(getActivity(), "连接出错", Toast.LENGTH_SHORT).show();
return;
}
writeFile(message);//这几个函数分别是写入发送消息到文件,写入收到的消息到文件以及刷新列表视图
writeFile(receive);
bindData();
}catch (Exception e) {
Toast.makeText(getActivity(), "发送失败", Toast.LENGTH_SHORT).show();
}
点9图处理
这个其实没什么好讲的,就两点:
- 1.如何生成点9图
导入一张图片到drawable文件夹下,右键它,选择Create 9-Patch file(应该是倒数第二个),生成完就在名字后面类型名前面加上了.9的后缀,然后就可以编辑了。 - 2.点9图的编辑
上、左为缩放区域,下右为文本显示区域。然后就是拖拖拖,一般把缩放的区域弄成一个像素的小点就可以了。
JSON数据处理
首先,有两个包,安卓下面org那个包不太好用,只能完成Json对象与字符串的转化(注意我说的是安卓),google那个GSON包可以轻松完成bean实体类对象与字符串之间的转化,所以我直接写成了静态类。
对象《=》json字符串
public class JsonDAO {
//传入bean对象,转为json字符串返回
//存储时调用
public static String getJson(Object object){
return new Gson().toJson(object);
}
//传入json字符串,转为对象返回
//读取时调用
public static Object getObjt(String jj,Class type){
Object o = new Gson().fromJson(jj,type);
return o;
}
}
json字符串《=》普通字符串
JSONObject json = new JSONObject(sb.toString());
if (json.getInt("code") == 100000) {
sb = new StringBuilder(json.getString("text"));
} else {
throw new CommonException("提交格式出錯");
}