环信UI开源Demo情景分析四、登陆界面
2015-04-24 08:36
357 查看
接下来咱们来分析下登录界面,根据清单文件的配置不难发现接下来的Activity基本都是竖屏显示,以及与启动界面一样的动画:
在下面的代码中有一处很神奇的逻辑,如果光从这个登录逻辑来看,不讨论以后的需要的话应该是不可能执行的:
没错,就是第五行,是不是有点熟悉,对,他就是在启动界面的逻辑,正因为没有登录才跳转到这个界面,结果在这个界面又判断一次,好吧,可能是以后有大用,先不管这个,咱们继续往下看,接下来是一个对用户名改变的监听,改变之后让密码清空。
最后面是对用户名的判断,咱们点进去看看到底是怎么存储用户名的:
这个是在APP类中的set,get方法通过Helper实例来保存的,至于到底保存在哪里了,后面碰到了再说。
在填完账号密码后就是可以登录了,首先是对网络状态的判断,
没有网的情况下会直接提示返回。假设当前咱们条件俱全,下面是对输入的判断,接下来启动一个有返回的AlertDialog并附带一些内容。
![](http://img.blog.csdn.net/20150424091627894?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2Fvd2VpMDQwMw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
很显然,这是一个自定义的对话框,功能是设置昵称。
设置了一下风格:
windowBackground:设置dialog的背景 默认的 windowBackground 定义为screen_background_dark,可以在frameworks\base\core\res\res\values\colors.xml
中找到,定义为:<drawable name="screen_background_dark">#ff000000</drawable> 现在设置为transparent 顺便说一下,如果自定义Theme中将android:windowBackground置为null,能小幅提升界面的绘制效率。
windowFrame:Dialog的windowFrame框为无
windowNoTitle:是否显示title
windowIsFloating:是否浮现在activity之上
windowIsTranslucent:是否半透明
windowContentOverlay:窗口内容的前景之上的可绘制资源。默认情况下,就是状态栏下的阴影
windowAnimationStyle:窗口动画风格 使用的是默认的
backgroundDimEnabled:背景是否模糊显示
显示
这个自定义的对画框说完了,接下来继续看这个对话框是怎能运作的。
其中有四个控件,分别显示标题、按钮、图案和一个编辑框。跟上面截图一样。
传过去的参数有:
这边获取到响应的内容:
先设置APP里的昵称,
登录界面就到这里了。按照正常流程,先注册一个账号,再继续往下。
<!-- 登陆 --> <activity android:name=".activity.LoginActivity" android:screenOrientation="portrait" android:theme="@style/horizontal_slide" > </activity>
在下面的代码中有一处很神奇的逻辑,如果光从这个登录逻辑来看,不讨论以后的需要的话应该是不可能执行的:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 如果用户名密码都有,直接进入主页面 if (DemoHXSDKHelper.getInstance().isLogined()) { autoLogin = true; startActivity(new Intent(LoginActivity.this, MainActivity.class)); return; } setContentView(R.layout.activity_login); usernameEditText = (EditText) findViewById(R.id.username); passwordEditText = (EditText) findViewById(R.id.password); // 如果用户名改变,清空密码 usernameEditText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { passwordEditText.setText(null); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } }); if (DemoApplication.getInstance().getUserName() != null) { usernameEditText.setText(DemoApplication.getInstance().getUserName()); } }
没错,就是第五行,是不是有点熟悉,对,他就是在启动界面的逻辑,正因为没有登录才跳转到这个界面,结果在这个界面又判断一次,好吧,可能是以后有大用,先不管这个,咱们继续往下看,接下来是一个对用户名改变的监听,改变之后让密码清空。
最后面是对用户名的判断,咱们点进去看看到底是怎么存储用户名的:
/** * 获取当前登陆用户名 * @return */ public String getUserName() { return hxSDKHelper.getHXId(); } /** * 设置用户名 * @param user */ public void setUserName(String username) { hxSDKHelper.setHXId(username); }
这个是在APP类中的set,get方法通过Helper实例来保存的,至于到底保存在哪里了,后面碰到了再说。
/** * 登录 * * @param view */ public void login(View view) { if (!CommonUtils.isNetWorkConnected(this)) { Toast.makeText(this, R.string.network_isnot_available, Toast.LENGTH_SHORT).show(); return; } currentUsername = usernameEditText.getText().toString().trim(); currentPassword = passwordEditText.getText().toString().trim(); if(TextUtils.isEmpty(currentUsername)){ Toast.makeText(this, R.string.User_name_cannot_be_empty, Toast.LENGTH_SHORT).show(); return; } if(TextUtils.isEmpty(currentPassword)){ Toast.makeText(this, R.string.Password_cannot_be_empty, Toast.LENGTH_SHORT).show(); return; } Intent intent = new Intent(LoginActivity.this, com.easemob.chatuidemo.activity.AlertDialog.class); intent.putExtra("editTextShow", true); intent.putExtra("titleIsCancel", true); intent.putExtra("msg", getResources().getString(R.string.please_set_the_current)); intent.putExtra("edit_text", currentUsername); startActivityForResult(intent, REQUEST_CODE_SETNICK); }
在填完账号密码后就是可以登录了,首先是对网络状态的判断,
/** * 检测网络是否可用 * @param context * @return */ public static boolean isNetWorkConnected(Context context) { if (context != null) { ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); if (mNetworkInfo != null) { return mNetworkInfo.isAvailable(); } } return false; }
没有网的情况下会直接提示返回。假设当前咱们条件俱全,下面是对输入的判断,接下来启动一个有返回的AlertDialog并附带一些内容。
很显然,这是一个自定义的对话框,功能是设置昵称。
<!-- 自定义的alertdialog --> <activity android:name=".activity.AlertDialog" android:screenOrientation="portrait" android:theme="@style/MyDialogStyle" > </activity>
<style name="MyDialogStyle"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowFrame">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:windowIsFloating">true</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> <item name="android:backgroundDimEnabled">true</item> </style>
设置了一下风格:
windowBackground:设置dialog的背景 默认的 windowBackground 定义为screen_background_dark,可以在frameworks\base\core\res\res\values\colors.xml
中找到,定义为:<drawable name="screen_background_dark">#ff000000</drawable> 现在设置为transparent 顺便说一下,如果自定义Theme中将android:windowBackground置为null,能小幅提升界面的绘制效率。
windowFrame:Dialog的windowFrame框为无
windowNoTitle:是否显示title
windowIsFloating:是否浮现在activity之上
windowIsTranslucent:是否半透明
windowContentOverlay:窗口内容的前景之上的可绘制资源。默认情况下,就是状态栏下的阴影
windowAnimationStyle:窗口动画风格 使用的是默认的
backgroundDimEnabled:背景是否模糊显示
显示
这个自定义的对画框说完了,接下来继续看这个对话框是怎能运作的。
mTextView = (TextView) findViewById(R.id.title); mButton = (Button) findViewById(R.id.btn_cancel); imageView = (ImageView) findViewById(R.id.image); editText = (EditText) findViewById(R.id.edit);
其中有四个控件,分别显示标题、按钮、图案和一个编辑框。跟上面截图一样。
传过去的参数有:
intent.putExtra("editTextShow", true); intent.putExtra("titleIsCancel", true); intent.putExtra("msg", getResources().getString(R.string.please_set_the_current)); intent.putExtra("edit_text", currentUsername);
这边获取到响应的内容:
//提示内容 String msg = getIntent().getStringExtra("msg"); //提示标题 String title = getIntent().getStringExtra("title"); position = getIntent().getIntExtra("position", -1); //是否显示取消标题 boolean isCanceTitle=getIntent().getBooleanExtra("titleIsCancel", false); //是否显示取消按钮 boolean isCanceShow = getIntent().getBooleanExtra("cancel", false); //是否显示文本编辑框 isEditextShow = getIntent().getBooleanExtra("editTextShow",false); //转发复制的图片的path String path = getIntent().getStringExtra("forwardImage"); // String edit_text = getIntent().getStringExtra("edit_text"); if(msg != null) ((TextView)findViewById(R.id.alert_message)).setText(msg); if(title != null) mTextView.setText(title); if(isCanceTitle){ mTextView.setVisibility(View.GONE); } if(isCanceShow) mButton.setVisibility(View.VISIBLE); if(path != null){ //优先拿大图,没有去取缩略图 if(!new File(path).exists()) path = DownloadImageTask.getThumbnailImagePath(path); imageView.setVisibility(View.VISIBLE); ((TextView)findViewById(R.id.alert_message)).setVisibility(View.GONE); if(ImageCache.getInstance().get(path) != null){ imageView.setImageBitmap(ImageCache.getInstance().get(path)); }else{ Bitmap bm = ImageUtils.decodeScaleImage(path, 150, 150); imageView.setImageBitmap(bm); ImageCache.getInstance().put(path, bm); } } if(isEditextShow){ editText.setVisibility(View.VISIBLE); editText.setText(edit_text); }然后根据所需要的,显示出来。就是我们所看到的。
public void ok(View view){ setResult(RESULT_OK,new Intent().putExtra("position", position). putExtra("edittext", editText.getText().toString()) /*.putExtra("voicePath", voicePath)*/); if(position != -1) ChatActivity.resendPos = position; finish(); } public void cancel(View view){ finish(); } @Override public boolean onTouchEvent(MotionEvent event){ finish(); return true; }其中还有两个按钮,以及非模态。并且设置返回内容为编辑框中的内容。
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == REQUEST_CODE_SETNICK) { DemoApplication.currentUserNick = data.getStringExtra("edittext"); progressShow = true; final ProgressDialog pd = new ProgressDialog(LoginActivity.this); pd.setCanceledOnTouchOutside(false); pd.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { progressShow = false; } }); pd.setMessage(getString(R.string.Is_landing)); pd.show(); final long start = System.currentTimeMillis(); // 调用sdk登陆方法登陆聊天服务器 EMChatManager.getInstance().login(currentUsername, currentPassword, new EMCallBack() { @Override public void onSuccess() { if (!progressShow) { return; } // 登陆成功,保存用户名密码 DemoApplication.getInstance().setUserName(currentUsername); DemoApplication.getInstance().setPassword(currentPassword); runOnUiThread(new Runnable() { public void run() { pd.setMessage(getString(R.string.list_is_for)); } }); try { // ** 第一次登录或者之前logout后再登录,加载所有本地群和回话 // ** manually load all local groups and // conversations in case we are auto login EMGroupManager.getInstance().loadAllGroups(); EMChatManager.getInstance().loadAllConversations(); // 处理好友和群组 processContactsAndGroups(); } catch (Exception e) { e.printStackTrace(); // 取好友或者群聊失败,不让进入主页面 runOnUiThread(new Runnable() { public void run() { pd.dismiss(); DemoApplication.getInstance().logout(null); Toast.makeText(getApplicationContext(), R.string.login_failure_failed, 1).show(); } }); return; } // 更新当前用户的nickname 此方法的作用是在ios离线推送时能够显示用户nick boolean updatenick = EMChatManager.getInstance().updateCurrentUserNick(DemoApplication.currentUserNick.trim()); if (!updatenick) { Log.e("LoginActivity", "update current user nick fail"); } if (!LoginActivity.this.isFinishing()) pd.dismiss(); // 进入主页面 startActivity(new Intent(LoginActivity.this, MainActivity.class)); finish(); } @Override public void onProgress(int progress, String status) { } @Override public void onError(final int code, final String message) { if (!progressShow) { return; } runOnUiThread(new Runnable() { public void run() { pd.dismiss(); Toast.makeText(getApplicationContext(), getString(R.string.Login_failed) + message, Toast.LENGTH_SHORT).show(); } }); } }); } } }这里面就是登录的内容了,
先设置APP里的昵称,
/** * 当前用户nickname,为了苹果推送不是userid而是昵称 */ public static String currentUserNick = "";然后设置一个圆形进度条,点击外部不退出,点击进度条取消。后面是调用SDK进行登录,并且保存用户名和密码,获取相关本地组和联系人信息。如果获取信息异常,则退出登录。成功后更新昵称。并且取消进度条,进入主界面。
private void processContactsAndGroups() throws EaseMobException { // demo中简单的处理成每次登陆都去获取好友username,开发者自己根据情况而定 List<String> usernames = EMContactManager.getInstance().getContactUserNames(); EMLog.d("roster", "contacts size: " + usernames.size()); Map<String, User> userlist = new HashMap<String, User>(); for (String username : usernames) { User user = new User(); user.setUsername(username); setUserHearder(username, user); userlist.put(username, user); } // 添加user"申请与通知" User newFriends = new User(); newFriends.setUsername(Constant.NEW_FRIENDS_USERNAME); String strChat = getResources().getString(R.string.Application_and_notify); newFriends.setNick(strChat); userlist.put(Constant.NEW_FRIENDS_USERNAME, newFriends); // 添加"群聊" User groupUser = new User(); String strGroup = getResources().getString(R.string.group_chat); groupUser.setUsername(Constant.GROUP_USERNAME); groupUser.setNick(strGroup); groupUser.setHeader(""); userlist.put(Constant.GROUP_USERNAME, groupUser); // 存入内存 DemoApplication.getInstance().setContactList(userlist); System.out.println("----------------" + userlist.values().toString()); // 存入db UserDao dao = new UserDao(LoginActivity.this); List<User> users = new ArrayList<User>(userlist.values()); dao.saveContactList(users); // 获取黑名单列表 List<String> blackList = EMContactManager.getInstance().getBlackListUsernamesFromServer(); // 保存黑名单 EMContactManager.getInstance().saveBlackList(blackList); // 获取群聊列表(群聊里只有groupid和groupname等简单信息,不包含members),sdk会把群组存入到内存和db中 EMGroupManager.getInstance().getGroupsFromServer(); }后面是获取联系人信息,并且对每个联系人这是header,方便查找。并保存到本地数据库当中。
/** * 设置hearder属性,方便通讯中对联系人按header分类显示,以及通过右侧ABCD...字母栏快速定位联系人 * @param username * @param user */ protected void setUserHearder(String username, User user) { String headerName = null; if (!TextUtils.isEmpty(user.getNick())) { headerName = user.getNick(); } else { headerName = user.getUsername(); } if (username.equals(Constant.NEW_FRIENDS_USERNAME)) { user.setHeader(""); } else if (Character.isDigit(headerName.charAt(0))) { user.setHeader("#"); } else { user.setHeader(HanziToPinyin.getInstance().get(headerName.substring(0, 1)).get(0).target.substring(0, 1).toUpperCase()); char header = user.getHeader().toLowerCase().charAt(0); if (header < 'a' || header > 'z') { user.setHeader("#"); } } }没有昵称用账号名,并且设置字幕前缀。
/** * 注册 * @param view */ public void register(View view) { startActivityForResult(new Intent(this, RegisterActivity.class), 0); } @Override protected void onResume() { super.onResume(); if (autoLogin) { return; } }对于11行,我很无解,不过不要在意这些细节。
登录界面就到这里了。按照正常流程,先注册一个账号,再继续往下。
相关文章推荐
- 环信UI开源Demo情景分析三、启动界面
- 环信UI开源Demo情景分析八、会话界面(补充)
- 环信UI开源Demo情景分析十一、聊天界面(三)
- 环信UI开源Demo情景分析五、注册界面
- 环信UI开源Demo情景分析七、会话界面
- 环信UI开源Demo情景分析六、主界面
- 环信UI开源Demo情景分析九、聊天界面(一)
- 环信UI开源Demo情景分析十二、聊天界面(四)
- 环信UI开源Demo情景分析十、聊天界面(二)
- 环信UI开源Demo情景分析一、项目概述
- 环信UI开源Demo情景分析二、清单文件
- 物联网平台机智云Android开源框架入门之旅(三)分析设备详情界面的中如何发送各种指令到云端。
- [Android]开源中国源码分析之一---启动界面
- "开源框架完美组合之Spring.NET + NHibernate + ASP.NET MVC + jQuery + easyUI 中英文双语言小型企业网站Demo"项目分析
- --@angularJS--较复杂的指令嵌套demo——综合小实例:登陆界面
- gina的智能卡登陆界面一点点分析.doc
- Android登陆界面设计demo
- android-async-http开源项目的GET方式或POST方式实现登陆案例简单Demo
- 登陆界面和进入文本界面Demo
- iOS微博显示界面Demo代码分析