帶有動畫的登錄界面制作

一、項目

做一個帶動畫的登陸界面,如下圖所示:


效果圖片

當點擊輸入密碼時,貓頭鷹的翅膀向上翻轉(zhuǎn),遮住眼睛。


遮住眼睛圖片

二、知識補充——屬性動畫

Android之前的補間動畫機制其實還算是比較健全的,在android.view.animation包下面有好多的類可以供我們操作,來完成一系列的動畫效果,比如說對View進行移動、縮放、旋轉(zhuǎn)和淡入淡出,并且我們還可以借助AnimationSet來將這些動畫效果組合起來使用,除此之外還可以通過配置Interpolator來控制動畫的播放速度等。補間動畫是只能夠作用在View上的。也就是說,我們可以對一個Button、TextView、甚至是LinearLayout、或者其它任何繼承自View的組件進行動畫操作,但是如果我們想要對一個非View的對象進行動畫操作,補間動畫就幫不上忙了。舉一個簡單的例子,比如說我們有一個自定義的View,在這個View當中有一個Point對象用于管理坐標,然后在onDraw()方法當中就是根據(jù)這個Point對象的坐標值來進行繪制的。也就是說,如果我們可以對Point對象進行動畫操作,那么整個自定義View的動畫效果就有了。顯然,補間動畫是不具備這個功能的,這是它的第一個缺陷。還有補間動畫只能夠?qū)崿F(xiàn)移動,縮放,旋轉(zhuǎn)和淡入淡出這四種動畫操作,不能對View的背景色進行改變。最后補間動畫只改變了view的效果而已,而沒有改變他的屬性。如果要改變view的屬性,就需要使用屬性動畫了


菜鳥教程

我們這個項目的動畫就是屬性動畫,貓頭鷹的翅膀旋轉(zhuǎn)上去之后還需要旋轉(zhuǎn)下來,轉(zhuǎn)之前的坐標和轉(zhuǎn)之后的坐標應該是不一樣的,但如果使用補間動畫旋轉(zhuǎn)之前后旋轉(zhuǎn)之后的坐標是一致的,這樣不利于翅膀的復原。

三、具體實現(xiàn)

1,在XML文件添加背景圖片,輸入框,文本框,圖像素材,按鈕等,還有調(diào)控它們的位置,還可以在背景上添加虛化層,需要導入第三方庫
build.gradle中添加

 implementation 'io.alterac.blurkit:blurkit:1.1.0'

并把 minSdkVersion 改成 21

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/bg"
    android:scaleType="fitXY"/>

<!--添加虛化層-->
<io.alterac.blurkit.BlurLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:blk_fps="0"
    app:blk_blurRadius="25">
</io.alterac.blurkit.BlurLayout>
<RelativeLayout
    android:layout_width="300dp"
    android:layout_height="200dp"
    android:layout_centerHorizontal="true"
    android:layout_alignTop="@id/bg"
    android:layout_marginTop="-100dp"
    >

    <ImageView
        android:id="@+id/iv_head"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:src="@drawable/owl" />
    <!--添加手掌-->
    <ImageView
        android:id="@+id/leftHand"
        android:layout_width="50dp"
        android:layout_height="60dp"
        android:src="@drawable/icon_hand"
        android:layout_alignParentLeft="true"
        android:layout_alignBottom="@id/iv_head"
        android:layout_marginBottom="-20dp"
        android:layout_marginLeft="10dp"/>
    <!--添加手掌-->
    <ImageView
        android:id="@+id/rightHand"
        android:layout_width="50dp"
        android:layout_height="60dp"
        android:src="@drawable/icon_hand"
        android:layout_alignParentRight="true"
        android:layout_alignBottom="@id/iv_head"
        android:layout_marginBottom="-20dp"
        android:layout_marginRight="10dp"/>
    <!--添加翅膀-->
    <ImageView
        android:id="@+id/iv_leftArm"
        android:layout_width="65dp"
        android:layout_height="40dp"
        android:src="@drawable/arm_left"
        android:layout_below="@id/iv_head"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="20dp"/>
    <ImageView
        android:id="@+id/iv_rightArm"
        android:layout_width="65dp"
        android:layout_height="40dp"
        android:src="@drawable/arm_right"
        android:layout_below="@id/iv_head"
        android:layout_alignParentRight="true"
        android:layout_marginRight="20dp"/>
</RelativeLayout>
<!--輸入框-->
<io.alterac.blurkit.BlurLayout
    android:id="@+id/bg"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:background="@drawable/inputbackgroundshape"
    android:layout_centerInParent="true"
    android:layout_marginLeft="20dp"
    android:layout_marginRight="20dp"
    app:blk_fps="0"/>
<!--添加標題和輸入框背景-->
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:layout_centerInParent="true"
    android:layout_marginLeft="20dp"
    android:layout_marginRight="20dp"
    android:orientation="vertical"
    android:padding="10dp"
    android:layout_marginTop="10dp"
    >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="登錄"
        android:textSize="20dp"
        android:textColor="#999999"
        android:textAlignment="center"
        />
    <EditText
        android:id="@+id/et_user"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@drawable/editor"
        android:layout_marginTop="10dp"
        android:drawableLeft="@drawable/iconfont_user"
        android:paddingLeft="7dp"
        android:drawablePadding="7dp"
        android:textSize="20dp"
        android:hint="請輸入用戶名"
        android:inputType="text"
        android:maxLines="1"
        />
    <EditText
        android:id="@+id/et_password"
       style="@style/EditorTextStyle"
        android:background="@drawable/editor"
        android:drawableLeft="@drawable/iconfont_password"
        android:inputType="textPassword"
        android:hint="請輸入密碼"/>
    <Button
        android:id="@+id/button_login"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="登錄"
        android:textColor="#ffffff"
        android:layout_marginTop="20dp"
        android:background="@drawable/loginbutton"
        android:enabled="false"/>
  </LinearLayout>
</RelativeLayout>

未添加虛化層效果展示:


圖片展示

其中輸入框的形狀在drawable文件里面配置

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dp"/>
<stroke android:width="1dp"
    android:color="#44000000"/>
</shape>

使用style抽離輸入框共有屬性

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--app中的標題,字體,字號,顏色
共同擁有的東西-->
<style name="EditorTextStyle">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">50dp</item>
    <item name="android:layout_marginTop">10dp</item>
    <item name="android:paddingLeft">7dp</item>
    <item name="android:drawablePadding">7dp</item>
    <item name="android:textSize">20dp</item>
    <item name="android:maxLines">1</item>
</style>

在drawable文件里面配置按鈕的形狀

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--正常狀態(tài)是一個圓角藍色矩形-->
<item >
    <shape android:shape="rectangle">
        <corners android:radius="5dp"/>
        <solid android:color="#39A4F9"/>
    </shape>
</item>
<!--無效狀態(tài)下-->
<item android:state_enabled="false">
    <shape android:shape="rectangle">
        <corners android:radius="5dp"/>
        <solid android:color="#66494343"/>
    </shape>
</item>
</selector>
</resources>

2,這樣就基本完成了素材的添加,接下來就需要為輸入框添加內(nèi)容和焦點改變事件,當有控件獲得焦點就會自動彈出鍵盤。

    //監(jiān)聽內(nèi)容改變,控制按鈕的點擊狀態(tài)
    user.addTextChangedListener(this);
    password.addTextChangedListener(this);
    //監(jiān)聽EditText的焦點變化,判斷是否需要捂住眼睛
    password.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if(hasFocus == true){
                //捂住眼睛
                //測試代碼
    //  Toast toast=  Toast.makeText(getApplicationContext(),"捂住眼睛",Toast.LENGTH_SHORT);
    //   toast.show();
                closeEye();
            }else{
        //打開眼睛
                open();
              }
          }
        });
    }

3,實現(xiàn)輸入框內(nèi)容改變事件回調(diào),管理登錄按鈕狀態(tài)

 @Override
  public void afterTextChanged(Editable s) {
    //判斷這兩個輸入框是否有內(nèi)容
    if(user.getText().toString().length() > 0&&
    password.getText().toString().length() > 0){
        //登錄按鈕可以點擊
        button.setEnabled(true);
    }else{
         //登錄按鈕不可以點擊
        button.setEnabled(false);
    }
}

4,監(jiān)聽touch事件,觸摸屏幕,隱藏鍵盤,相應的輸入框失去焦點

@Override
public boolean onTouchEvent(MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        //隱藏鍵盤
        //1,獲取系統(tǒng)輸入的管理器
       InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
        //2,隱藏軟鍵盤
        inputMethodManager.hideSoftInputFromWindow(user.getWindowToken(),0);

        //3,取消焦點
        View focusView = getCurrentFocus();
        if(focusView != null) {
            focusView.clearFocus(); //取消焦點
        }

        //focusView.requestFocus();//請求焦點
        //簡單方式
        //getCurrentFocus().clearFocus();
    }
    return true;
}

5,創(chuàng)建一個anim文件,在里面配置手掌向上和向下的動畫


image.png

向上移動的文件和這個一致,只是移動的方向相反
6,給貓頭鷹的兩個翅膀添加旋轉(zhuǎn)動畫

  //捂眼睛
public void closeEye(){
    // 左邊 旋轉(zhuǎn)翅膀
    //創(chuàng)建一個旋轉(zhuǎn)動畫
    RotateAnimation rotateAnimation1 = new RotateAnimation(0,170,leftArm.getWidth(),0f);
    rotateAnimation1.setDuration(600);
    //旋轉(zhuǎn)后保持狀態(tài)
    rotateAnimation1.setFillAfter(true);
    leftArm.startAnimation(rotateAnimation1);

    //創(chuàng)建一個旋轉(zhuǎn)動畫
    RotateAnimation rotateAnimation2 = new RotateAnimation(0,-170,0f,0f);
    rotateAnimation2.setDuration(600);
    //旋轉(zhuǎn)后保持狀態(tài)
    rotateAnimation2.setFillAfter(true);
    rightArm.startAnimation(rotateAnimation2);

    TranslateAnimation translateAnimation = (TranslateAnimation) AnimationUtils.loadAnimation(this,R.anim.hand_down);
    leftHand.startAnimation(translateAnimation);
    rightHand.startAnimation(translateAnimation);
}
public void open(){
    // 左邊 旋轉(zhuǎn)翅膀
    //創(chuàng)建一個旋轉(zhuǎn)動畫
    RotateAnimation rotateAnimation1 = new RotateAnimation(170,0,leftArm.getWidth(),0f);
    rotateAnimation1.setDuration(600);
    //旋轉(zhuǎn)后保持狀態(tài)
    rotateAnimation1.setFillAfter(true);
    leftArm.startAnimation(rotateAnimation1);

    //創(chuàng)建一個旋轉(zhuǎn)動畫
    RotateAnimation rotateAnimation2 = new RotateAnimation(-170,0,0f,0f);
    rotateAnimation2.setDuration(600);
    //旋轉(zhuǎn)后保持狀態(tài)
    rotateAnimation2.setFillAfter(true);
    rightArm.startAnimation(rotateAnimation2);

    TranslateAnimation translateAnimation = (TranslateAnimation) AnimationUtils.loadAnimation(this,R.anim.hand_up);

    leftHand.startAnimation(translateAnimation);
    rightHand.startAnimation(translateAnimation);

}

效果展示:

展示

錄制屏幕時當點擊輸入密碼時錄制的內(nèi)容是黑屏,目前還沒解決……
MainActivity完整代碼

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity implements TextWatcher {
private EditText user;
private EditText password;
private Button button;
private ImageView leftArm;
private ImageView rightArm;
private ImageView leftHand;
private ImageView rightHand;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //調(diào)用
    initView();
}
//初始化
public void initView(){

    user = findViewById(R.id.et_user);
    password = findViewById(R.id.et_password);
    button = findViewById(R.id.button_login);
    leftArm = findViewById(R.id.iv_leftArm);
    rightArm = findViewById(R.id.iv_rightArm);
    leftHand = findViewById(R.id.leftHand);
    rightHand = findViewById(R.id.rightHand);

    //監(jiān)聽內(nèi)容改變,控制按鈕的點擊狀態(tài)
    user.addTextChangedListener(this);
    password.addTextChangedListener(this);
    //監(jiān)聽EditText的焦點變化,判斷是否需要捂住眼睛
    password.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if(hasFocus == true){
                //捂住眼睛
                //測試代碼
//  Toast toast=  Toast.makeText(getApplicationContext(),"捂住眼睛",Toast.LENGTH_SHORT);
//     toast.show();
                closeEye();
            }else{
                open();
            }
        }
    });
}
/**
 * 當有控件獲得焦點focus,自動彈出鍵盤
 * 1,點擊軟鍵盤的enter鍵 自動收回鍵盤
 * 2,代碼控制 InputMentionManager
 * showSoftInput:顯示鍵盤
 * @param event
 * @return
 */
@Override
public boolean onTouchEvent(MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        //隱藏鍵盤
        //1,獲取系統(tǒng)輸入的管理器
       InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
        //2,隱藏軟鍵盤
        inputMethodManager.hideSoftInputFromWindow(user.getWindowToken(),0);

        //3,取消焦點
        View focusView = getCurrentFocus();
        if(focusView != null) {
            focusView.clearFocus(); //取消焦點
        }

        //focusView.requestFocus();//請求焦點
        //簡單方式
        //getCurrentFocus().clearFocus();

    }
    return true;
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

}

@Override
public void afterTextChanged(Editable s) {
    //判斷這兩個輸入框是否有內(nèi)容
    if(user.getText().toString().length() > 0&&
    password.getText().toString().length() > 0){
        //按鈕可以點擊
        button.setEnabled(true);
    }else{
        button.setEnabled(false);
    }
}
//捂眼睛
public void closeEye(){
    // 左邊 旋轉(zhuǎn)翅膀
    //創(chuàng)建一個旋轉(zhuǎn)動畫
    RotateAnimation rotateAnimation1 = new RotateAnimation(0,170,leftArm.getWidth(),0f);
    rotateAnimation1.setDuration(600);
    //旋轉(zhuǎn)后保持狀態(tài)
    rotateAnimation1.setFillAfter(true);
    leftArm.startAnimation(rotateAnimation1);

    //創(chuàng)建一個旋轉(zhuǎn)動畫
    RotateAnimation rotateAnimation2 = new RotateAnimation(0,-170,0f,0f);
    rotateAnimation2.setDuration(600);
    //旋轉(zhuǎn)后保持狀態(tài)
    rotateAnimation2.setFillAfter(true);
    rightArm.startAnimation(rotateAnimation2);

    TranslateAnimation translateAnimation = (TranslateAnimation) AnimationUtils.loadAnimation(this,R.anim.hand_down);
    leftHand.startAnimation(translateAnimation);
    rightHand.startAnimation(translateAnimation);



}
public void open(){
    // 左邊 旋轉(zhuǎn)翅膀
    //創(chuàng)建一個旋轉(zhuǎn)動畫
    RotateAnimation rotateAnimation1 = new RotateAnimation(170,0,leftArm.getWidth(),0f);
    rotateAnimation1.setDuration(600);
    //旋轉(zhuǎn)后保持狀態(tài)
    rotateAnimation1.setFillAfter(true);
    leftArm.startAnimation(rotateAnimation1);

    //創(chuàng)建一個旋轉(zhuǎn)動畫
    RotateAnimation rotateAnimation2 = new RotateAnimation(-170,0,0f,0f);
    rotateAnimation2.setDuration(600);
    //旋轉(zhuǎn)后保持狀態(tài)
    rotateAnimation2.setFillAfter(true);
    rightArm.startAnimation(rotateAnimation2);

    TranslateAnimation translateAnimation = (TranslateAnimation) AnimationUtils.loadAnimation(this,R.anim.hand_up);

    leftHand.startAnimation(translateAnimation);
    rightHand.startAnimation(translateAnimation);

    }
}

四、寫在最后

學習的主要內(nèi)容主要是屬性動畫的使用,所以密碼設置這一塊并沒有做,因為之前寫過用用戶偏好保存密碼所以這里就沒有具體寫。還有手機屏幕錄制時點擊輸入密碼后錄制的一段是黑屏,百度之后發(fā)現(xiàn)這是應用的自身策略。密碼界面調(diào)起安全輸入法的時候,系統(tǒng)自帶的錄屏功能、第三方的錄屏軟件無法錄制屏幕,截取結(jié)果是黑屏。這是由于安全輸入法在此做了訪問控制,避免你的密碼被泄露,讓你的手機更加安全。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容