最近终于得空闲了下来= =,所以来整理一下当做练手的第一个App(花了大概10天,期间还有一门概率论……)和帮学长改App的一些经验什么的。
自定义控件
控件水真心很深,感觉如果想要对这个有一个比较好的理解的话需要下很大功夫。当然这和我基础浅有很大关系。整理一下发现这次自定义的控件有如下几个:
1 TopBar
2 EditText
3 ListView
4 Button
下面一个个来讲。
TopBar
顶栏是一个执念,实际上我感觉我的App并不需要顶栏。
需要注意的一点就是,这个是大自定义控件,是新写了一个继承RelativeLayout的类,还有它的点击事件类,同时,在value文件夹里新建了一个attr的xml文件,用来定义它的属性。
主类、点击事件类、xml属性都不是我写的,我只能看懂,并且修改,不过目前我也只能做到这样╮(╯_╰)╭而且用起来比想象中还是要难的,主要是布局文件中很容易出错。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.moplast.app"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background1" >
<!-- 顶栏 -->
<com.moplast.custom.TopBar
android:id="@+id/topBar_main"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#000000"
custom:leftText=""
custom:leftTextColor="#FFFFFF"
custom:rightText="菜单"
custom:rightTextColor="#FFFFFF"
custom:title="欢迎<未知用户>"
custom:titleTextColor="#FFFFFF" >
</com.moplast.custom.TopBar>
需要注意的是RelativeLayout中这个属性
xmlns:custom。 custom指定了一个标签,也就是下面代码中所有的那些属性引导标签,都是custom,而不是安卓工具包里自带的android。因为顶栏封装了左右按钮和标题,所以左右按钮和标题都可以修改文字、字体大小和字体颜色。
EditText
为什么要重写这个类呢?是因为我想做一个相对来说比较漂亮的登陆界面,而我对安卓自带的EditText的橙色边框实在是深恶痛绝。
EditText的重写相对来说比较容易,只要在drawable文件夹中新增一个xml文件指定一种新的形状即可:
以下为转载
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<!-- 填充 -->
<solid
android:color="#E7FFC9" />
<!-- 边框 -->
<stroke
android:width="0.4dip"
android:color="#000000" />
<!-- 圆角 -->
<corners
android:bottomLeftRadius="15dip"
android:bottomRightRadius="15dip"
android:topLeftRadius="15dip"
android:topRightRadius="15dip" />
</shape>
这个形状重新定义了EditText的边框和填充颜色(自己修改了一下~),而且相对来说圆角矩形看起来会舒服一点,所以用了圆角的属性。通过更改Radius也是可以改圆角的弧度,和网页一样一样的。
关于它的应用:
<EditText
android:id="@+id/password"
android:layout_width="200dip"
android:layout_height="35dip"
android:layout_below="@+id/username"
android:layout_centerHorizontal="true"
android:layout_marginTop="28dp"
<span style="color:#FF0000;"> android:background="@drawable/edittext_settings"</span>
android:ems="10"
android:gravity="center"
android:hint="●●●●●●●●"
android:inputType="textPassword"
android:singleLine="true"
android:textColorHint="#AAAAAA"
android:textSize="16sp" />
标红的显然是重点咯,就是把背景图片变成自己定义的那个xml构成的图形。
ListView
selector是个很重要的东西,真的很重要/w\。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_selected="true" android:drawable="@color/transparent"/>
</selector>
其实这样并没有满足我的需求,因为它仅仅是把ListView点击时的橙色背景变成透明而已,即点击时没有明显变化。而ListView的很多别的属性却暂时没找到更改=-=。
常见的是把ListView中的Item绑定,具有丰富的内容,且针对一个Item中的不同内容,可以分别绑定不同的监听,这个就得重写ListView。然而这次我没有那么复杂的需求,虽然以后的开发中这个不可避免,不过:)下次再说吧。这个一定也会单独开一篇文章来特地说。
(说你妹!上次的JSON都没说!)
Button
button控件的重写几乎已经成了必然,因为实在是丑,丑,丑。重要的事情要说三次。
button_selector_green.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/clr_normal"
android:state_pressed="false"/>
<item
android:drawable="@drawable/clr_pressed"
android:state_pressed="true"/>
</selector>
这个是按钮被按下时的选择器,应该是颜色变深了一些。而对于按钮形状,则需要用shape来解决。
layout_lg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<!-- 边框 -->
<stroke
android:width="0.4dip"
android:color="#000000" />
<!-- 渐变色 -->
<gradient
android:angle="0"
android:centerX="0.5"
android:centerY="0.5"
android:endColor="#D4FF52"
android:startColor="#7CCF11"
android:type="linear" />
<!-- 圆角 -->
<corners
android:bottomLeftRadius="15dip"
android:bottomRightRadius="15dip"
android:topLeftRadius="15dip"
android:topRightRadius="15dip" />
<!-- 边距 -->
<padding android:left="0dip"
android:top="0dip"
android:right="0dip"
android:bottom="0dip"/>
</shape>
其实我在想,如果我既需要改变按钮的形状,又需要绑定选择器,我该怎么办,因为从以下的布局文件中可以看到,这些都是在background属性里的。
按理来说,我应该在同一个xml文件中,有两个分立的<selector>和<shape>尝试一下,看看能不能一起实现。
——然后我就发现,不能= =。
<Button
android:id="@+id/LogIn"
android:layout_width="200dip"
android:layout_height="35dip"
android:layout_alignLeft="@+id/password"
android:layout_below="@+id/password"
android:layout_marginTop="28dp"
android:background="@drawable/layout_lg"
android:text="Log In"
android:textColor="#FFFFFF"
android:textSize="16sp" />
<Button
android:id="@+id/upLocaToServer"
android:layout_width="200dp"
android:layout_height="35dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="110dp"
android:background="@drawable/button_selector_green"
android:text="上传我的位置"
android:textColor="#FFFFFF"
android:alpha="0.8"/>
然后我就找方法~在这里找到了方法→http://www.cnblogs.com/top5/archive/2012/05/10/2494763.html
同时也多学到了一些shape和selector的属性。同时里面还有一个漂亮的list_item!感觉赚大发了!(我够……)
方法就是:selector里面套shape。
看一看下面的例子好了——
selector_shape_button.xml
<selector xmlns:Android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<!--选中时的图片背景,看代码是一个圆角的渐变的……呃,矩形?-->
<shape>
<gradient
android:angle="270"
android:endColor="#99BD4C"
android:startColor="#A5D245" />
<size
android:height="60dp"
android:width="320dp" />
<corners
android:radius="8dp" />
</shape>
</item>
<item Android:state_pressed="true">
<!--单击时的图片背景-->
<shape>
<gradient Android:angle="270" android:endColor="#99BD4C"
android:startColor="#A5D245"/>
<size Android:height="60dp" android:width="320dp" />
<corners android:radius="8dp" />
</shape>
</item>
<item>
<!-- 一般情况下的图片背景 -->
<shape>
<gradient Android:angle="270" android:endColor="#A8C3B0"
android:startColor="#C6CFCE" />
<size Android:height="60dp" android:width="320dp" />
<corners android:radius="8dp" />
</shape>
</item>
</selector>
搜索功能+查询数据库+ListView显示
因为我是新手,所以遇到这个的时候还是花了一点时间,而且感觉并不是最优的方案,不过姑且贴一贴。
简单来说,这个功能的定义是:根据关键字查找相关用户,并添加其好友。
客户端_搜索+ListView显示
package com.moplast.app;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import com.moplast.service.BasicSetting;
import com.moplast.service.GetResponse;
import com.moplast.service.JsonArrayConvert;
public class SearchActivity extends Activity{
<span style="color:#660000;"> private List<Map<String,Object>> sList=new ArrayList<Map<String,Object>>();//与ListView绑定的ArrayList
private EditText search;//搜索的关键字输入
private Button search_go;//按下按钮,搜索
private ListView searchResults;//在ListView中显示返回的结果
private String userId="1";//初始化userId</span>
protected void onStart(){
super.onStart();
setContentView(R.layout.search);
init();
//获得userId
Intent intent=this.getIntent();
Bundle bundle=intent.getExtras();
userId=(String)bundle.get("userId");
//按下搜索按钮的时候处理逻辑
search_go.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//首先,获取edittext里面的内容。
String searchText=search.getText().toString();
//将searchText的内容发送给服务器,让服务器处理并返回结果。
//返回的JSON数据应该是所有符合查询的username和isOnlined状态。
HttpPost hPost=new HttpPost(getString(R.string.postUri)+"Search");
List<NameValuePair> params=new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("searchText",searchText));
sList.clear();
try {
String JsonResult=new GetResponse().getResponse(hPost,params);
<span style="color:#009900;"> //由于返回的是数组格式,所以这次用parseJsonMulti来解析
Map<String,Object> searchResult_mapt=parseJsonMulti(JsonResult);</span>
<span style="color:#3366FF;">
//接收两个数组存放着username和isOnlined,和符合的用户记录条数i
String[] username=(String[])searchResult_mapt.get("username");
int[] isOnlined=(int[])searchResult_mapt.get("isOnlined");
int i=(Integer) searchResult_mapt.get("num");
</span>
for (int j=0;j<i;j++){
Map<String,Object> searchResult_map=new HashMap<String, Object>();
searchResult_map.put("userPic",R.drawable.contact);
searchResult_map.put("username",username[j]);
searchResult_map.put("isOnlined",isOnlined[j]);
sList.add(searchResult_map);
}
ListAdapter listAdapter=new SimpleAdapter(
SearchActivity.this,
sList,
R.layout.search_list,
new String []{"userPic","username","isOnlined"},
new int[]{R.id.userPic,R.id.username_s,R.id.isOnlined_s});
searchResults.setAdapter(listAdapter);
//处理ListView中的点击事件
searchResults.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//添加好友请求
String ContactName=(String) sList.get(position).get("username");
final HttpPost hPost=new HttpPost(getString(R.string.postUri)+"ContactsAdd");
final List<NameValuePair> params=new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("ContactsName",ContactName));
params.add(new BasicNameValuePair("UserId",userId));
AlertDialog.Builder builder=new AlertDialog.Builder(SearchActivity.this);
builder.setTitle("添加好友");
builder.setMessage("确认添加好友吗?");
builder.setPositiveButton("确定",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try {
String JsonResult=new GetResponse().getResponse(hPost,params);
//解析flag即可
parseJson(JsonResult);
}catch(Exception e){
Toast.makeText(SearchActivity.this, "添加失败", Toast.LENGTH_SHORT);
}
}
});
builder.setNegativeButton("取消",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
builder.show();
}
});
} catch (Exception e) {
Toast.makeText(SearchActivity.this, "搜索失败", 1).show();
}
}
});
}
protected void parseJson(String strResult){
try {
JSONObject jsonObjs = new
JSONObject(strResult).getJSONObject("Add");
int flag = jsonObjs.getInt("flag");
if(flag==0){
Toast.makeText(SearchActivity.this, "添加失败", Toast.LENGTH_LONG).show();
}else if(flag==1){
Toast.makeText(SearchActivity.this, "添加成功", Toast.LENGTH_LONG).show();
}else if(flag==2){
Toast.makeText(SearchActivity.this, "该用户已是您的好友,请不要重复添加", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
System.out.println("Json parse error");
}
}
protected Map<String, Object> parseJsonMulti(String strResult) {
Map<String,Object> searchResult_map=new HashMap<String, Object>();
try {
JSONObject jsonObjs = new
JSONObject(strResult).getJSONObject("Search");
//flag=0,不存在相符用户;flag=1,存在,并返回数组
int flag = jsonObjs.getInt("flag");
if(flag==0){
Toast.makeText(SearchActivity.this, "未搜索到相关用户", Toast.LENGTH_LONG);
}else if(flag==1){
JSONArray usernameArray = jsonObjs.getJSONArray("username");
String[] username = JsonArrayConvert.getJsonToStringArray(usernameArray);
int i = usernameArray.length();
JSONArray isOnlinedArray = jsonObjs.getJSONArray("isOnlined");
int[] isOnlined = JsonArrayConvert.getJsonToIntArray(isOnlinedArray);
searchResult_map.put("username", username);
searchResult_map.put("isOnlined", isOnlined);
searchResult_map.put("num", i);
}
} catch (JSONException e) {
System.out.println("Json parse error");
}
return searchResult_map;
}
private void init(){
new BasicSetting().initStrictMode();
search=(EditText)findViewById(R.id.search);
search_go=(Button)findViewById(R.id.searchGo);
searchResults=(ListView)findViewById(R.id.searchResults);
}
}
服务器端_查询数据库
package com.moplast.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Array;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import com.moplast.jdbc.DBConnection;
import com.moplast.utils.ConvertEncoding;
import com.moplast.utils.DateFormat;
public class Search extends HttpServlet {
Map<String, Object> mapt = new HashMap<String, Object>();
int flag=0;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request,response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//用户名获取
String searchText = request.getParameter("searchText");
//SQL语句的构建
String sql = "SELECT * FROM user_info WHERE username LIKE '%"
+searchText
+"%'";
try {
DBConnection dbutil = new DBConnection();
ResultSet rs=dbutil.GetRs(sql);
int i=0;
while(rs.next()){
i++;
}
if(i!=0){
String[] username=new String [i];
int[] isOnlined= new int [i];
i=0;
rs.beforeFirst();
while(rs.next()){
flag=1;
username[i]=rs.getString("username");
isOnlined[i]=rs.getInt("isOnlined");
i++;
}
mapt.put("username", username);
mapt.put("isOnlined", isOnlined);
}
} catch (SQLException e) {
System.out.println("未能成功更新数据");
e.printStackTrace();
}
Map<String,Object>map=new HashMap<String,Object>();
mapt.put("flag", flag);
map.put("Search",mapt);
//实例化Gson包
Gson gson = new Gson();
String result = gson.toJson(map);
response.getWriter().write(result);
}
}
百度地图API运用
之前怎么都没办法让定位不在天安门(我都快吐了)。学长貌似写好了,我稍微改了改。。。存个档。不过这个不是主要的,主要的应该是在CopyOfMainActivity里面。
public class MapActivity extends Activity {
private MapView mMapView;
private TextView tv;
private BaiduMap mBaiduMap;
LocationClient mLocClient;
private LocationReceiver locationReceiver = null;
private LocationMode mCurrentMode;
BitmapDescriptor mCurrentMarker;
// UI相关
OnCheckedChangeListener radioButtonListener;
Button requestLocButton;
boolean isFirstLoc = true;// 是否首次定位
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_map);
tv = (TextView) findViewById(R.id.tv);
requestLocButton = (Button) findViewById(R.id.button1);
mCurrentMode = LocationMode.NORMAL;
requestLocButton.setText("普通");
OnClickListener btnClickListener = new OnClickListener() {
public void onClick(View v) {
switch (mCurrentMode) {
case NORMAL:
requestLocButton.setText("跟随");
mCurrentMode = LocationMode.FOLLOWING;
mBaiduMap
.setMyLocationConfigeration(new MyLocationConfiguration(
mCurrentMode, true, mCurrentMarker));
break;
case COMPASS:
requestLocButton.setText("普通");
mCurrentMode = LocationMode.NORMAL;
mBaiduMap
.setMyLocationConfigeration(new MyLocationConfiguration(
mCurrentMode, true, mCurrentMarker));
break;
case FOLLOWING:
requestLocButton.setText("罗盘");
mCurrentMode = LocationMode.COMPASS;
mBaiduMap
.setMyLocationConfigeration(new MyLocationConfiguration(
mCurrentMode, true, mCurrentMarker));
break;
}
}
};
requestLocButton.setOnClickListener(btnClickListener);
// 地图初始化
mMapView = (MapView) findViewById(R.id.bmapView);
locationReceiver = new LocationReceiver();
mBaiduMap = mMapView.getMap();
//设置交通流量图。。。为true
// mBaiduMap.setTrafficEnabled(true);
//普通地图
// mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
//卫星地图
//mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
/*LatLng cenpt = new LatLng(31.824052,119.986812);
MapStatus mMapStatus = new MapStatus.Builder().target(cenpt).zoom(19).build();
MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
mBaiduMap.setMapStatus(mapStatusUpdate);*/
}
@Override
protected void onStart() {
super.onStart();
IntentFilter intentFilter = new IntentFilter(LocationUtil.LOCATION_ACTTION);
registerReceiver(locationReceiver, intentFilter);
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
LocationUtil.start(getApplicationContext());
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
mMapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
unregisterReceiver(locationReceiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
mMapView.onDestroy();
}
private class LocationReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if(intent != null){
LocationBean locationBean =
(LocationBean) intent.getSerializableExtra(LocationUtil.LOCATION_KEY);
//在textview中显示地址详细信息
tv.setText(locationBean.getAddloc());
// 构造定位数据
MyLocationData locData = new MyLocationData.Builder()
.accuracy((float) locationBean.getRad())
// 此处设置开发者获取到的方向信息,顺时针0-360
.direction(100).latitude(locationBean.getLat())
.longitude(locationBean.getLot()).build();
// 当不需要定位图层时关闭定位图层
mBaiduMap.setMyLocationEnabled(true);
LatLng point = new LatLng(locData.latitude,locData.longitude);
// 图标
BitmapDescriptor bitmap = BitmapDescriptorFactory
.fromResource(R.drawable.red);
OverlayOptions option = new MarkerOptions()
.position(point)
.icon(bitmap)
.zIndex(1);
Marker marker = (Marker) (mBaiduMap.addOverlay(option));
//在地图上添加Marker,并显示
mBaiduMap.addOverlay(option);
MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(point);
mBaiduMap.setMapStatus(u);
/**
* 万达的点
*/
LatLng point2 = new LatLng(31.824317,119.976826);
// 图标
BitmapDescriptor bitmap2 = BitmapDescriptorFactory
.fromResource(R.drawable.red);
OverlayOptions option2 = new MarkerOptions()
.position(point2)
.icon(bitmap)
.zIndex(2);
Marker marker2 = (Marker) (mBaiduMap.addOverlay(option2));
//在地图上添加Marker,并显示
mBaiduMap.addOverlay(option2);
MapStatusUpdate u2 = MapStatusUpdateFactory.newLatLng(point2);
mBaiduMap.setMapStatus(u2);
/*//设置中心点
LatLng cenpt = new LatLng(locationBean.getLat(),locationBean.getLot());
MapStatus mMapStatus = new MapStatus.Builder().target(cenpt).build();
MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
mBaiduMap.setMapStatus(mapStatusUpdate);*/
// 设置定位图层的配置(定位模式,是否允许方向信息,用户自定义定位图标)
/*mCurrentMarker = BitmapDescriptorFactory
.fromResource(R.drawable.icon_geo);
mCurrentMarker = null;
MyLocationConfiguration config = new MyLocationConfiguration(mCurrentMode, true, mCurrentMarker);
mBaiduMap.setMyLocationConfigeration(config); */
mBaiduMap.setOnMarkerClickListener(new OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker arg0) {
// TODO Auto-generated method stub
Intent intent=new Intent();
intent.setClass(MapActivity.this, FindStallActivity.class);
startActivity(intent);
overridePendingTransition(android.R.anim.fade_in,android.R.anim.fade_out);
return false;
}
});
}
}
}
}
【先这样,好累= =】