当然,在登陆之前还是有其他界面的,比如第一次登陆时会有欢迎导航界面,,启动应用时会显示logo界面。下一篇再介绍。
logo界面结束之后会进入登陆界面,当然,前提是没有自动登陆的用户(有自动登陆的用户,是跳过登陆界面,直接进入主界面的)。
登陆界面由两个输入框,两个可选按钮,两个按钮组成。界面虽然简单,但是费了很大的劲处理,简单罗列如下:
在输入框的左边显示一个头像,右边是一个一键清空的小叉叉;
输入学号时会自动匹配已登录过的用户,如果登录时勾选了记住密码时,选择了用户后会自动填充密码;
当用户名或密码为空时点击登录按钮,为空的输入框会抖动,并会有红色字体提示为空;
勾选自动登陆后,下次打开应用就会直接以该用户的账户自动登陆,而不会显示登陆界面。
首先是,带有头像和叉叉的输入框
代码如下:
public class ClearEditText extends EditText implements
OnFocusChangeListener, TextWatcher {
/**
* 删除按钮的引用
*/
private Drawable mClearDrawable;
/**
* 控件是否有焦点
*/
private boolean hasFoucs;
public ClearEditText(Context context) {
this(context, null);
}
public ClearEditText(Context context, AttributeSet attrs) {
//这里构造方法也很重要,不加这个很多属性不能再XML里面定义
this(context, attrs, android.R.attr.editTextStyle);
}
public ClearEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
//获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
mClearDrawable = getCompoundDrawables()[2];
if (mClearDrawable == null) {
// throw new NullPointerException("You can add drawableRight attribute in XML");
mClearDrawable = getResources().getDrawable(R.drawable.delete_selector);
}
mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
//默认设置隐藏图标
setClearIconVisible(false);
//设置焦点改变的监听
setOnFocusChangeListener(this);
//设置输入框里面内容发生改变的监听
addTextChangedListener(this);
}
/**
* 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件
* 当我们按下的位置 在 EditText的宽度 - 图标到控件右边的间距 - 图标的宽度 和
* EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向就没有考虑
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (getCompoundDrawables()[2] != null) {
boolean touchable = event.getX() > (getWidth() - getTotalPaddingRight())
&& (event.getX() < ((getWidth() - getPaddingRight())));
if (touchable) {
this.setText("");
}
}
}
return super.onTouchEvent(event);
}
/**
* 当ClearEditText焦点发生变化的时候,判断里面字符串长度设置清除图标的显示与隐藏
*/
@Override
public void onFocusChange(View v, boolean hasFocus) {
this.hasFoucs = hasFocus;
if (hasFocus) {
setClearIconVisible(getText().length() > 0);
} else {
setClearIconVisible(false);
}
}
/**
* 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
* @param visible
*/
protected void setClearIconVisible(boolean visible) {
Drawable right = visible ? mClearDrawable : null;
setCompoundDrawables(getCompoundDrawables()[0],
getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
}
/**
* 当输入框里面内容发生变化的时候回调的方法
*/
@Override
public void onTextChanged(CharSequence s, int start, int count,
int after) {
if(hasFoucs){
setClearIconVisible(s.length() > 0);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
/**
* 设置晃动动画
*/
public void setShakeAnimation(){
this.setAnimation(shakeAnimation(5));
}
/**
* 晃动动画
* @param counts 1秒钟晃动多少下
* @return
*/
public static Animation shakeAnimation(int counts){
Animation translateAnimation = new TranslateAnimation(0, 10, 0, 0);
translateAnimation.setInterpolator(new CycleInterpolator(counts));
translateAnimation.setDuration(1000);
return translateAnimation;
}
}
在定义输入框时:
<cn.edu.wit.withelper.util.ClearEditText
android:id="@+id/userid"
android:layout_weight="1"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:background="@drawable/et_userid_border"
android:drawableLeft="@drawable/users_selector"
android:drawableRight="@drawable/delete_selector"
android:hint="请输入您的学号"
android:inputType="number"
android:focusableInTouchMode="true"
android:padding="3dp"
android:singleLine="true"
android:textSize="25sp" />
抖动的动画也在上面定义了,
下面就介绍下拉列表,
ib_spinner = (ImageButton) findViewById(R.id.ib_spinner);//一个图片,覆盖到输入框的右端
ib_spinner.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 弹出下拉列表
ListView listView = new ListView(getApplicationContext());
listView.setCacheColorHint(0x00000000);// 滑动时 不变色
listView.setVerticalScrollBarEnabled(false);
listView.setBackgroundColor(getResources().getColor(R.color.white));
//设置透明度
listView.getBackground().setAlpha(230);
listView.setAdapter(new MyAdapter());
pop = new PopupWindow(listView, etUserId.getWidth()+ib_spinner.getWidth(),
LayoutParams.WRAP_CONTENT, true);
// pop隐藏
pop.setBackgroundDrawable(new ColorDrawable(0x00000000));
pop.setOutsideTouchable(true);
pop.setFocusable(true);
// pop.setAnimationStyle(R.style.PopupAnimation);
pop.showAsDropDown(etUserId, 0, -8);
pop.update();
}
});
接下来就是,记住密码与自动登陆了
if (1 == isAuto) { //自动登录则存入数据库,且写到配置文件
SharedPreferencesUtil.saveLoginUser(LoginActivity.this, user);
userInfoServices.insertUserInfo(user);
}else if (1 == isRemember) { //记住密码就写入数据库
userInfoServices.insertUserInfo(user);
}
登陆成功后,就根据用户的选择,对数据进行处理
然后就是,如何实现登陆
public static UserInfo login(UserInfo loginUser) {
String URL = "http://www.******.com/API/Android/Login";
final Map<String, String> params = new HashMap<String, String>();
params.put("userID", loginUser.getUserId());
params.put("password", loginUser.getPassword());
JSONObject jsonResult = InterfaceUtil.getJSONObject(URL, params);
if (jsonResult == null) {
Log.i(TAG, "result = null");
return loginUser;
} else {
Log.i(TAG, "result = " + jsonResult.toString());
return getUserByJson(jsonResult, loginUser);
}
}
public static JSONObject getJSONObject(
String url, // 请求的URL
Map<String, String> params // 请求的参数序列
) {
long timestamp = new Date().getTime();
//时间戳
params.put("timestamp", "" + timestamp);
//sign
params.put("sign", MD5Util.getMD5String(SALT + timestamp));
String result = postRequestToServer(url, params);
if (null == result) {
Log.i(TAG, "result = null");
return null;
}else {
Log.i(TAG, "result = " + result);
JSONTokener jsonTokener = new JSONTokener(result);
JSONObject json = null;
try {
json = (JSONObject) jsonTokener.nextValue();
} catch (JSONException e) {
e.printStackTrace();
} finally {
return json;
}
}//end of else
}
这里就涉及到对网络的访问,对json的解析,以及对数据的封装
public static String postRequestToServer(String url, // 请求的URL
Map<String, String> params // 请求的参数序列
) {
Log.i(TAG, "访问网络");
HttpEntityEnclosingRequestBase httpRequest = new HttpPost(url);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(params.size());
for (Map.Entry<String, String> entry : params.entrySet()) {// 构建表单字段内容
nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
String strResult = "";
try {
httpRequest.setEntity(new UrlEncodedFormEntity(nameValuePairs,"UTF-8"));
HttpClient client = new DefaultHttpClient();
HttpParams httpparams = client.getParams();
HttpConnectionParams.setConnectionTimeout(httpparams,7000);
HttpConnectionParams.setSoTimeout(httpparams,7000);
// 执行请求
HttpResponse httpResponse = client.execute(httpRequest);
// 判断返回结果,200则说明正确返回
if (httpResponse.getStatusLine().getStatusCode() == 200) {
// 从返回的结果中获取内容
strResult = EntityUtils.toString(httpResponse.getEntity(),"UTF-8");
} else {
strResult = null;
}
} catch (Exception e) {
e.printStackTrace();
Message msg = new Message();
msg.what = Task.ERROR_NETEXCEPTION ;
msg.obj = e;
MainService.handler.sendMessage(msg);
strResult = null;
} finally {
return strResult;
}
}
本应用中,所有的网络访问都是通过这个函数实现的
还有一个获取网络图片的函数,在本应用中没有使用,是准备用来获取用户头像的
/**
* 通过url获取图片
* @param url
* @return
*/
public static Drawable getNetImage(URL url) {
if (null == url)
return null;
try {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
return Drawable.createFromStream(connection.getInputStream(),"image");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
还有一个就是对SharedPreferences的操作;
/**
* 保存登录用户信息
* @param context
* @param user
*/
public static void saveLoginUser(Context context, UserInfo user) {
SharedPreferences sp = context.getSharedPreferences(LOGIN_USER, Context.MODE_PRIVATE);
Editor editor = sp.edit();
editor.putString(UserInfo.USERID, user.getUserId());
editor.putString(UserInfo.SESSIONID, user.getSessionId());
editor.putString(UserInfo.USERNAME, user.getUserName());
editor.commit();
}
/**
* 获取登录用户信息
* @param context
* @return
*/
public static UserInfo getLoginUser(Context context) {
SharedPreferences sp = context.getSharedPreferences(LOGIN_USER, Context.MODE_PRIVATE);
String userId = sp.getString(UserInfo.USERID, "");
String session = sp.getString(UserInfo.SESSIONID, "");
String userName = sp.getString(UserInfo.USERNAME, "");
if ("".equals(userId))
return null;
UserInfo user = new UserInfo();
user.setUserId(userId);
user.setSessionId(session);
user.setUserName(userName);
return user;
}
登陆差不多就这么些东西,现在看来有很多东西都太low了,但还是原汁原味地展示出来。明天把项目的源码上传到github上,有时间就修改一下,希望有兴趣,或者有心赐教的大神多多指点。
ps:自动获取标签太烂了
本文出自 “年少的风” 博客,谢绝转载!