zoukankan      html  css  js  c++  java
  • Android开发系列(十一) QQ登陆界面——Android控件使用实例

      这是新年第一弹,这几天家里有些闹心的事,直到现在还没解决,所以一直未更新博客。不过这两个夜晚的时间做了一个QQ登录界面(2013版),其实我早就想做这么一个界面,只是前一段时间还没有复习太多的东西,现在在处理那些烦心事的零散时间做出来了基本的界面,也算是值得高兴的事情吧。

      话不多说,这次因为可能讲的内容比较多,可能会分两次讲,所以首先先上图,以便对最终实现能够达到什么养的效果心中有数。

    这是手机QQ2013官方版的登录界面:

    这个是我自己做出来的 QQ登录界面:

    当然与官方版相比还是有很大的差距,不过对于学习安卓控件的使用已经足够了。

      为实现上述界面,需要有几个关键的知识点需要学习:

    一、实现圆角的效果——学会使用描述背景的drawable/中的 xml文件

      需要在drawable文件夹中创建xml文件,文件的父控件类型为shape,在shape父控件中,有<solid/>  <corners/> <stroke/> <padding/> 等属性,分别处理背景的填充颜色、边角的曲率、边框线的宽度和颜色、上下左右内边框(即背景超出使用改背景的空间的宽度)

         例如,若想实现一个圆角的ImageButton,可以创建一个 fillet_shape.xml文件

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
        <solid android:color="#ffffff"/>
        <corners android:radius="10px"/>
        <padding android:left="3dip" android:top="3dip" android:right="3dip" android:bottom="3dip"/>
        
    </shape>

    然后在Activity类中用ImageButton的实例设置setBackgroundResource(); 或者在xml布局文件中在配置控件属性使用  android:background="@drawable/fillet_shape"
    注意这里在配置好背景之后,在为ImageView设置显示的图片时,只能使用setImageResource()而不能使用setBackgroundResource();

    学会这点很重要,后面就可以举一反三,本例中使用该方法为 EditText设置了边框,为ListView的每一个Item设置了边框,为按钮设置了圆角背景。就不再特殊说明

    二、RelativeLayout中控件的布局问题

      不同控件之间是可以覆盖的,注意在布局文件中后配置的空间可以覆盖掉之前配置的空间,所以本例在布局文件中让ListView控件放在了最后,另外如果想要一个控件暂时消失

    可以使用setVisibility(View.GONE);的方法,这样改控件消失以后被覆盖的空间就可以正常使用了。另外本例在EditText中添加按钮并没有自定义EditText,而是直接通过布局文件的描述将联系人游标(小箭头)嵌在了Edittext中。注意这里一般不使用View.INVISIBLE,这样控件并未消失

    三、notifyDataSetChanged方法是BaseAdapter的方法,所以可以在构造的适配器内部或者创建的适配器对象使用。

    四、并不是只有Button可以设置OnClickListener  实际上很多常见的空间都可以使用,如EditText或者TextView ,这个应该是属于View的抽象方法

    五、ListView如何调整每一个Item边框的宽度并且避免Item之间的分割线颜色太深?

          方法就是上面介绍的自定义drawable/ 中xml文件,来配置边和背景属性,另外在配置ListView控件的属性时 设置android:divider="#aaaaaa" android:dividerHeight="0px"  这样可以是ListItem的边框做出上图所示的效果。

    六、怎样解决ListView中添加Button之后就不响应单击事件的问题?

      原因是Button抢夺了焦点,最简单的解决办法是:在自定义的每一个ListItem的布局文件中在根标签的属性中添加上 android:descendantFocusability="blocksDescendants" 即拒绝ListItem中的子控件获得焦点

    七、怎样实现在点击某个控件以外的屏幕区域就使该控件消失的效果?本例中实现在点击ListView以外的区域就会使ListView消失的效果。

    方法是覆写MainActivity的onTouchEvent()方法,根据点击的坐标(x,y)与目标控件通过getLocation获得的控件左上角坐标,再结合目标控件的宽和高,判断点击的点是否在控件内,进而决定对该控件执行怎样的操作。

    例子:

    @Override
        public boolean onTouchEvent(MotionEvent event) {
            // TODO Auto-generated method stub
            if(event.getAction()==MotionEvent.ACTION_DOWN && isVisible){
                int[] location=new int[2];
                //调用getLocationInWindow方法获得某一控件在窗口中左上角的横纵坐标
                loginList.getLocationInWindow(location);
                //获得在屏幕上点击的点的坐标
                int x=(int)event.getX();  
                int y=(int)event.getY();
                if(x<location[0]|| x>location[0]+loginList.getWidth() ||
                        y<location[1]||y>location[1]+loginList.getHeight()){
                    isIndicatorUp=false;
                    isVisible=false;
                    
                    
                    listIndicatorButton.setBackgroundResource(R.drawable.indicator_down);
                    loginList.setVisibility(View.GONE);   //让ListView列表消失,并且让游标向下指!
                    
                }
                
                
            }
            
            
            return super.onTouchEvent(event);
        }


    以上就是我在写程序的过程中遇到的一些难题,天有些晚了,直接上所有的代码吧。。

    首先布局文件activity_main.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context=".MainActivity"
        android:background="#dde1ee" >
    
        <ImageView 
            android:id="@+id/myImage"
            android:layout_width="70dip"
            android:layout_height="70dip"
            android:layout_marginTop="65dip"
            android:layout_centerHorizontal="true"
            android:background="@drawable/fillet_shape"/>
        <EditText 
            android:id="@+id/qqNum"
            android:layout_width="match_parent"
            android:layout_height="40dip"
            android:layout_marginLeft="30dip"
            android:layout_marginRight="30dip"
            android:layout_marginTop="15dip"
            android:paddingLeft="50dip"
            android:layout_below="@id/myImage"
            android:inputType="number"
            android:background="@drawable/qqnum_edit"/>
        
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="账号"
            android:textSize="8pt"
            android:textColor="@android:color/darker_gray"
            android:layout_alignLeft="@id/qqNum"
            android:layout_alignTop="@id/qqNum"
            android:layout_marginTop="9dip"
            android:layout_marginLeft="3dip"/>
        
        <EditText 
            android:id="@+id/qqPassword"
            android:layout_width="match_parent"
            android:layout_height="40dip"
            android:paddingLeft="50dip"
            android:layout_marginLeft="30dip"
            android:layout_marginRight="30dip"
            android:layout_below="@id/qqNum"
            android:background="@drawable/qqnum_edit"/>
        
         <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="密码"
            android:textSize="8pt"
            android:textColor="@android:color/darker_gray"
            android:layout_alignLeft="@id/qqPassword"
            android:layout_alignTop="@id/qqPassword"
            android:layout_marginTop="9dip"
            android:layout_marginLeft="3dip"/>
    
         <ImageButton
             android:id="@+id/qqListIndicator"
             android:layout_width="22dip"
             android:layout_height="20dip"
             android:layout_marginBottom="8dip"
             android:layout_marginRight="3dip"
             android:layout_alignBottom="@+id/qqNum"
             android:layout_alignRight="@+id/qqNum"
             android:background="@drawable/indicator_down" />
         <ImageButton 
             android:id="@+id/delete_button_edit"
             android:layout_width="18dip"
             android:layout_height="18dip"
             android:layout_marginBottom="8dip"
             android:layout_marginRight="3dip"
             android:layout_alignBottom="@+id/qqNum"
             android:layout_toLeftOf="@id/qqListIndicator"
             android:background="@drawable/delete_button_edit"
             android:visibility="gone"/>
         
         <Button 
             android:id="@+id/qqLoginButton"
             android:layout_width="match_parent"
             android:layout_height="35dip"
             android:layout_below="@id/qqPassword"
             android:layout_alignLeft="@id/qqNum"
             android:layout_alignRight="@id/qqNum"
             android:layout_marginTop="20dip"
             
             android:background="@drawable/login_button_back"
             android:text="登录"
             android:textColor="@android:color/white"/>
         <TextView 
             android:id="@+id/fetchPassword"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             
             android:layout_alignParentBottom="true"
             android:layout_alignParentLeft="true"
             android:layout_below="@id/qqLoginButton"
             android:layout_marginLeft="45dip"
             android:text="找回密码"
             android:textSize="7pt"
             android:textColor="#333355"
             android:gravity="bottom"/>
         
         <TextView 
             android:id="@+id/registQQ"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_below="@id/qqLoginButton"
             android:layout_alignParentBottom="true"
             android:layout_alignParentRight="true"
             android:layout_marginRight="45dip"
             android:layout_marginTop="5dip"
             android:text="注册账号"
             android:textSize="7pt"
             android:textColor="#333355"
             android:gravity="bottom"/>
         
         <TextView 
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_below="@id/qqLoginButton"
             android:text="|"
             android:textSize="7pt"
             android:layout_alignParentBottom="true"
             android:layout_centerHorizontal="true"
             android:gravity="bottom"/>
         
         <ListView
             android:id="@+id/loginQQList"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_above="@id/registQQ"
             android:layout_alignLeft="@id/qqNum"
             android:layout_alignRight="@id/qqNum"
             android:layout_below="@id/qqNum"
             android:focusable="true"
             android:focusableInTouchMode="true"
             android:visibility="gone"
             android:divider="#aaaaaa"
             android:dividerHeight="0px"/>
    
    </RelativeLayout>


    listItem的布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="35dip"
        android:orientation="horizontal"
        android:background="@drawable/list_item_border"
        android:descendantFocusability="blocksDescendants" >
        
        <ImageView 
            android:id="@+id/login_userPhoto"
            android:layout_width="match_parent"
            android:layout_weight="4.7"
            android:layout_height="30dip"
            android:background="@drawable/contact_1"
            android:layout_marginLeft="10dip"
            android:layout_marginTop="5dip"
            android:layout_marginRight="15dip"
            android:layout_marginBottom="5dip"/>
    
        <TextView
            android:id="@+id/login_userQQ"
            android:layout_width="match_parent"
            android:layout_height="30dip"
            android:layout_marginTop="5dip"
            android:layout_weight="2"
            android:gravity="center_vertical"
            android:text="1234567890"
            android:textSize="7pt" />
    
        <ImageButton
            android:id="@+id/login_deleteButton"
            android:layout_width="match_parent"
            android:layout_weight="5.8"
            android:layout_height="14dip"
            android:layout_marginTop="11dip"
            android:layout_marginRight="3dip"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:background="@drawable/deletebutton" />
    
    </LinearLayout>


    至于实现圆角等边框效果的xml布局文件就不再添加,上面第一条已经给出例子,可以根据需要的效果进行推广。

    然后就是MainActivity文件,这里为了适配器类等够对Activity界面进行更改,将适配器类写成了MainActivity类的内部类,代码中有说明。另外相当一部分代码是为了实现一些细节性的东西,如EditText中游标的的方向变化,图片图案的变化,使用了一些常量。

    package com.example.android_qq_login;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import com.qqlist.contactor.UserInfo;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.Menu;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.View.OnClickListener;
    import android.widget.*;
    import android.widget.AdapterView.OnItemClickListener;
    import android.widget.AdapterView.OnItemSelectedListener;
    
    public class MainActivity extends Activity {
    
        TextView textFetchPassWord=null,textRegister=null;
        Button loginButton=null;
        ImageButton  listIndicatorButton=null, deleteButtonOfEdit=null;
        ImageView currentUserImage=null;
        ListView loginList=null;
        EditText qqEdit=null, passwordEdit=null;
        private static boolean isVisible=false;         //ListView是否可见
        private static boolean isIndicatorUp=false;     //指示器的方向
        
        public static int currentSelectedPosition=-1;    
        //用于记录当前选择的ListView中的QQ联系人条目的ID,如果是-1表示没有选择任何QQ账户,注意在向
        //List中添加条目或者删除条目时都要实时更新该currentSelectedPosition
        
        String[] from={"userPhoto","userQQ","deletButton"};
        int[] to={R.id.login_userPhoto,R.id.login_userQQ,R.id.login_deleteButton};
        ArrayList<HashMap<String,Object>> list=null;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            textFetchPassWord=(TextView)findViewById(R.id.fetchPassword);
            textRegister=(TextView)findViewById(R.id.registQQ);
            loginButton=(Button)findViewById(R.id.qqLoginButton);
            listIndicatorButton=(ImageButton)findViewById(R.id.qqListIndicator);
            loginList=(ListView)findViewById(R.id.loginQQList);
            list=new ArrayList<HashMap<String,Object>>();
            currentUserImage=(ImageView)findViewById(R.id.myImage);
            qqEdit=(EditText)findViewById(R.id.qqNum);
            passwordEdit=(EditText)findViewById(R.id.qqPassword);
            deleteButtonOfEdit=(ImageButton)findViewById(R.id.delete_button_edit);
            
            qqEdit.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    if(qqEdit.getText().toString().equals("")==false){
                        deleteButtonOfEdit.setVisibility(View.VISIBLE);
                    }
                    
                }
            });
            
            deleteButtonOfEdit.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    currentUserImage.setImageResource(R.drawable.qqmain);
                    qqEdit.setText("");
                    currentSelectedPosition=-1;
                    deleteButtonOfEdit.setVisibility(View.GONE);
                    
                }
            });
            
            UserInfo user1=new UserInfo(R.drawable.contact_0,"1234567",R.drawable.deletebutton);
            UserInfo user2=new UserInfo(R.drawable.contact_1,"10023455",R.drawable.deletebutton);
            addUser(user1);
            addUser(user2);
            
            //设置当前显示的被选中的账户的头像
            if(currentSelectedPosition==-1){
                currentUserImage.setImageResource(R.drawable.qqmain);
                qqEdit.setText("");
            }
            else{
                currentUserImage.setImageResource((Integer)list.get(currentSelectedPosition).get(from[0]));
                qqEdit.setText((String)list.get(currentSelectedPosition).get(from[1]));
            }
            
            MyLoginListAdapter adapter=new MyLoginListAdapter(this, list, R.layout.layout_list_item, from, to);
            loginList.setAdapter(adapter);
            loginList.setOnItemClickListener(new OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                        long arg3) {
                    // TODO Auto-generated method stub
                    currentUserImage.setImageResource((Integer)list.get(arg2).get(from[0]));
                    qqEdit.setText((String)list.get(arg2).get(from[1]));
                    currentSelectedPosition=arg2;
                    
                    //相应完点击后List就消失,指示箭头反向!
                    loginList.setVisibility(View.GONE);
                    listIndicatorButton.setBackgroundResource(R.drawable.indicator_down);
                    
                    System.out.println("---------Selected!!");
                    
                }
    
        
            });
            
            listIndicatorButton.setOnClickListener(new OnClickListener(){
    
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    if(isIndicatorUp){
                        isIndicatorUp=false;
                        isVisible=false;
                        listIndicatorButton.setBackgroundResource(R.drawable.indicator_down);
                        loginList.setVisibility(View.GONE);   //让ListView列表消失
                        
                    }
                    else{
                        isIndicatorUp=true;
                        isVisible=true;
                        listIndicatorButton.setBackgroundResource(R.drawable.indicator_up);
                        loginList.setVisibility(View.VISIBLE);
                    }
                }
                
            });
            
        
        }
    
        
        //继承onTouchEvent方法,用于实现点击控件之外的部分使控件消失的功能
        
        
        
        
        private void addUser(UserInfo user){
            HashMap<String,Object> map=new HashMap<String,Object>();
            map.put(from[0], user.userPhoto);
            map.put(from[1], user.userQQ);
            map.put(from[2], user.deleteButtonRes);
            
            list.add(map);
        }
        
        
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // TODO Auto-generated method stub
            if(event.getAction()==MotionEvent.ACTION_DOWN && isVisible){
                int[] location=new int[2];
                //调用getLocationInWindow方法获得某一控件在窗口中左上角的横纵坐标
                loginList.getLocationInWindow(location);
                //获得在屏幕上点击的点的坐标
                int x=(int)event.getX();  
                int y=(int)event.getY();
                if(x<location[0]|| x>location[0]+loginList.getWidth() ||
                        y<location[1]||y>location[1]+loginList.getHeight()){
                    isIndicatorUp=false;
                    isVisible=false;
                    
                    
                    listIndicatorButton.setBackgroundResource(R.drawable.indicator_down);
                    loginList.setVisibility(View.GONE);   //让ListView列表消失,并且让游标向下指!
                    
                }
                
                
            }
            
            
            return super.onTouchEvent(event);
        }
    
        
        
        
        
        /**
         * 为了便于在适配器中修改登录界面的Activity,这里把适配器作为
         * MainActivity的内部类,避免了使用Handler,简化代码
         * @author DragonGN
         *
         */
        
        public class MyLoginListAdapter extends BaseAdapter{
    
            protected Context context;
            protected ArrayList<HashMap<String,Object>> list;
            protected int itemLayout;
            protected String[] from;
            protected int[] to;
            
            
              
            
            public MyLoginListAdapter(Context context,
                    ArrayList<HashMap<String, Object>> list, int itemLayout,
                    String[] from, int[] to) {
                super();
                this.context = context;
                this.list = list;
                this.itemLayout = itemLayout;
                this.from = from;
                this.to = to;
            }
    
            @Override
            public int getCount() {
                // TODO Auto-generated method stub
                return list.size();
            }
    
            @Override
            public Object getItem(int arg0) {
                // TODO Auto-generated method stub
                return null;
            }
    
            @Override
            public long getItemId(int position) {
                 // TODO Auto-generated method stub
                return position;
            }
    
            class ViewHolder{
                public ImageView userPhoto;
                public TextView userQQ;
                public ImageButton deleteButton;
            }
            
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                // TODO Auto-generated method stub
                ViewHolder holder=null;
                /*
                currentPosition=position;    
                不能使用currentPosition,因为每绘制完一个Item就会更新currentPosition
                这样得到的currentPosition将始终是最后一个Item的position        
                */
                
                if(convertView==null){
                    convertView=LayoutInflater.from(context).inflate(itemLayout, null);
                    holder=new ViewHolder();
                    holder.userPhoto=(ImageView)convertView.findViewById(to[0]);
                    holder.userQQ=(TextView)convertView.findViewById(to[1]);
                    holder.deleteButton=(ImageButton)convertView.findViewById(to[2]);
                    convertView.setTag(holder);
                }
                else{
                    holder=(ViewHolder)convertView.getTag();
                }
                
                holder.userPhoto.setBackgroundResource((Integer)list.get(position).get(from[0]));
                holder.userQQ.setText((String)list.get(position).get(from[1]));
                holder.deleteButton.setBackgroundResource((Integer)list.get(position).get(from[2]));
                holder.deleteButton.setOnClickListener(new ListOnClickListener(position));
                
                return convertView;
            }
            
            class ListOnClickListener implements OnClickListener{
    
                private int position;
                
                
                public ListOnClickListener(int position) {
                    super();
                    this.position = position;
                }
    
                @Override
                public void onClick(View arg0) {
                        // TODO Auto-generated method stub
                    list.remove(position);
                    
                    //如果删除的就是当前显示的账号,那么将主界面当前显示的头像设置回初始头像
                    if(position==currentSelectedPosition){
                        currentUserImage.setImageResource(R.drawable.qqmain);
                        qqEdit.setText("");
                        currentSelectedPosition=-1;
                    }
                    else if(position<currentSelectedPosition){
                        currentSelectedPosition--;    //这里小于当前选择的position时需要进行减1操作
                    }
                    
                    listIndicatorButton.setBackgroundResource(R.drawable.indicator_down);
                    loginList.setVisibility(View.GONE);   //让ListView列表消失,并且让游标向下指!
                    
                    MyLoginListAdapter.this.notifyDataSetChanged();    
                    
                    
                }
                
            }
            
    
        }
    
    
    }

    另外再多附几张效果图:

     

    大概就这些了,赶紧去休息。

  • 相关阅读:
    Java反射获取对象VO的属性值(通过Getter方法)
    HTML的级联Select
    ORACLE 新增记录 & 更新记录
    ORACLE 仿照原表建表语法
    ActiveMQ反序列化漏洞(CVE-2015-5254)复现
    滥用DNSAdmins权限进行Active Directory提权
    Weblogic CVE-2018-3191远程代码命令执行漏洞复现
    Libssh认证绕过CVE-2018-10933漏洞复现
    Linux kernel(CVE-2018-17182)提权漏洞复现
    时间延迟盲注详解
  • 原文地址:https://www.cnblogs.com/carlos-vic/p/Carlos_V_Android_11.html
Copyright © 2011-2022 走看看