【助手APP】登陆

延续大学时做课程设计的思路,首先就是登陆

当然,在登陆之前还是有其他界面的,比如第一次登陆时会有欢迎导航界面,,启动应用时会显示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:自动获取标签太烂了

时间: 2024-10-06 06:54:31

【助手APP】登陆的相关文章

大三上学期安卓一边学一边开始做一个自己觉得可以的项目 广商小助手App 加油

这项目构思好多 一个人一步一步来 一边做一边为后面应用铺设 广商小助手APP 设计出的软件登录场景 实现(算是可以) 界面大体出来了 界面点击方面也做了很多特效 上图其实点击各颜色后会出现各种图和反应 当然还有好多东西没弄 当前时代都看脸一个不精美的软件少人用 所以多花心思 项目还在努力中>>>>>>>

开源基于百度地图SDK的Android交通助手App

BaiduMap-TrafficAssistant ?? 该项目是基于百度地图SDK开发的一款交通助手App,目前已经上线豌豆荚.魅族应用市场.搜狗手机助手等多个安卓应用市场.目前我决定开源该项目,为更多的安卓应用开发者或者基于百度地图SDK开发人员提供服务和便利.当然App中还有不少bug和可扩展的功能模块,也希望各位开发者为该项目贡献自己的code力量.项目地址:https://github.com/chenyufeng1991/BaiduMap-TrafficAssistant 1.项目简

订阅号助手App发布 手机也能管理公众号了

盼着许久的微信订阅号助手app终于发布了!“ 微信团队发布「订阅号助手」App,支持公众号运营者在手机上发表内容.查看和回复消息.管理已关注用户和帐号.暂时只支持iOS平台,Android平台敬请期待.”订阅号助手App有哪些功能呢?随ytkah一起来看看吧 实时互动 1. 可以及时收到留言消息,进行回复.精选和置顶.2. 可以及时收到赞赏并回复.3. 可以及时收到已关注用户的私信消息,实时沟通. 移动发表 1. 可以在手机上编辑并发表图文.图片和文字消息.编辑图文消息时可以添加图片和音乐.2.

房屋出租小助手APP需求分析

房屋出租小助手APP是专为个人房东管理出租房而开发的APP应用,主要功能有租客管理(利用人工智能自动识别租客×××,无需人工录入),房间管理,出租管理,水电抄表管理,水电费管理,押金管理,收款管理,×××管理,财务统计,房租支付管理,上传头像,上传微信&支付宝支付码,在线升级,修改密码等功能.该系统采用Jsp技术,使用SSM框架,Mysql数据库,ajax技术及人工智能等相关技术实现. 项目开发技术:java,jsp,mysql,MyBatis,SpringMVC,jquery,ajax,jso

flutter-lol云顶之弈助手app

前两天利用业余时间开发了一个云顶助手app,所以来分享一下使用flutter的经验和看法. 先贴一个项目地址:https://github.com/Purelightme/lol_chess 可以给个小星星吗? 因为wegame上面已经有云顶相关的资料了,比较健全,但是是需要联网才能用的,经常网络慢(也可能是wegame服务器卡了)刷新不出来东西,我就想着这些英雄,装备,羁绊不都是固定的数据吗,何不把他们做成本地的,不需要网络,这样也更快,体验更好. 恰好flutter支持sqlite数据库,于

《智能背诵助手APP》作品构思与设计

<智能背诵助手APP>作品构思与设计——朱梓练 <智能背诵助手APP>作品从2018年12月9号构思,2019年3月20日开发完成,该APP能帮助中小学生背诵课文和古诗文,同时也能帮助各行各业的用户背诵其他中文材料. 本人在早读背诵时想到为什么不做一个智能背诵助手来辅助我背诵古诗文或课文呢,目前很多同学在背诵时常常需要另一个人充当聆听者和裁判,因为自己独自背诵很容易发生的问题是①背漏背错,自己却不知道:②对于不确定的部分会不自觉地偷看,然后继续背诵,造成自我欺骗:③在找人背诵时可能

App登陆java后台处理和用户权限验证

最近做一个app项目,后台我独自一人开发,开发任务顺序安排上没有把登陆,注册和权限验证这些基本功能放在第一阶段开发,现在是部分业务相关功能已经完成,但是用户入口竟然还没有,只能说明当初需求分析的时候还是太过于着急了,把最基本的用户入口给放到后面了. 现在就需要在现有代码的基础上添加用户登录和权限验证功能. 关于登录和权限验证方面,参照以前做iOS的开发经验,App端提供用户名和密码换取token,每次通过换取的token请求需要登陆权限的操作. 现在反过来,我就需要考虑下面几个问题: 1.在现有

【助手APP】简介及框架

最近没有怎么编码,就把断断续续做了半年的毕业设计拿出来回顾一下. 校园助手,分为服务器端与Android客户端,在此主要介绍客户端,服务器是一位大神用node.js写的. 主要实现的功能有:登陆,信息查询,地图,订餐,网页的调用与解析,主要费劲的就是界面. 客户端的框架是参照网上讲解新浪微博客户端的视频.在现在的工作中经常遇到界面更新的不便,但是这个框架就很解决了这个问题,只是刚入门的我还不知道,遇到很多挫折之后才发现这个框架的便捷.下面就开始简单描述一下: public class MainS

app逆向入门分析——APP登陆请求参数

环境配置: PyhtonJavadex2jar(将apk反编译成java源码)jd_gui(源码查看)jadx已root的手机或者安卓模拟器fiddler 分析: 首先我们用fiddler抓包工具对app的登陆进行抓包,这个app抓包需要开启全局代理,不然会抓不到数据. 如果还不会使用全局代理抓包的朋友,可以看下前面一篇文章,里面有详细的抓包教程. 抓包的数据如下:               <ignore_js_op> 发送验证码请求参数 我们可以看到有个 token 的参数,有经验的朋友