Android開發系列 QQ登陸界面——Android控件使用實例 - Carlos.V

本文轉載自:http://www.tuicool.com/articles/iy6Zvyn

這是手機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>
<?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();    
                
                
            }
            
        }
        

    }


}

另外再多附幾張效果圖:

 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章