Android百分比布局支持和垂直TextView

时间:2020-02-23 14:29:08  来源:igfitidea点击:

在本教程中,我们将讨论并实现Android Percent Layout支持库。
此外,我们将创建一个垂直TextView。
最后,我们将把这两个概念合并在一起,在我们的应用程序中编写有趣的登录屏幕设计概念。

Android百分比布局支持概述

Android API 23引入了对Android Percent Layout的支持。
该库使我们可以为" layout_width"," layout_height"和" layout_margin"指定百分比值。

因此,PercentRelativeLayout是一个RelativeLayout,具有为子视图分配权重的附加功能(类似PercentFrameLayout),这是LinearLayouts中一直存在的功能。

因此,我们可以对百分比布局中存在的子视图组件的宽度,高度,边距设置一个百分比(满分为100)。

PercentRelativeLayout和PercentFrameLayout帮助我们降低了视图的复杂度,因为我们不再被迫使用LinearLayout封装子视图并为子视图使用权重。

要使用百分比布局支持,请将以下依赖项添加到build.gradle文件中。
compile'com.android.support:percent:25.3.1'

添加以上依赖项后,我们就可以在应用程序中使用" android.support.percent.PercentRelativeLayout"和" android.support.percent.PercentFrameLayout"。

结果,我们现在可以分别用PercentRelativeLayout和PercentFrameLayout替换xml中的RelativeLayout和FrameLayout标记。

Android百分比支持布局示例

让我们看一看" layout_widthPercent"的示例实现。

app:layout_widthPercent:其中我们以百分比设置视图宽度。

注意:在PercentRelativeLayout中,如果我们指定了layout_widthPercent或者layout_heightPercent属性,那么layout_widthlayout_height属性是可选的。

sample.xml代码

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.theitroad.percentlayouts.MainActivity">

  <TextView
      android:layout_height="wrap_content"
      android:text="Hello World!"
      android:textSize="20sp"
      app:layout_widthPercent="75%" 

</android.support.percent.PercentRelativeLayout>

输出:
We've set the layout_widthPercentto 75 in the above implementation. In addition, setting it to 100 would be equivalent to match_parent. We can implement the other layout params that are given below in a similar manner.- layout_heightPercent

  • layout_marginPercent
  • layout_marginLeftPercent`
  • layout_marginRightPercent`
  • layout_marginTopPercent
  • layout_marginBottomPercent`
  • layout_marginStartPercent
  • layout_marginEndPercent

Android垂直TextView

我们使用的标准TextView小部件仅水平显示文本。
因此,我们将创建一个自定义TextView,使我们可以垂直显示文本。

下面是VerticalTextView.java类的代码:

package com.theitroad.verticaltextviewandpercentlayout;

import android.content.Context;
import android.graphics.Canvas;
import android.support.v7.widget.AppCompatTextView;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.Gravity;

public class VerticalTextView extends AppCompatTextView {
  final boolean topDown;

  public VerticalTextView(Context context, AttributeSet attrs) {
      super(context, attrs);
      final int gravity = getGravity();
      if (Gravity.isVertical(gravity) && (gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) {
          setGravity((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP);
          topDown = false;
      } else
          topDown = true;

  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(heightMeasureSpec, widthMeasureSpec);
      setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
  }

  @Override
  protected void onDraw(Canvas canvas) {
      TextPaint textPaint = getPaint();
      textPaint.setColor(getCurrentTextColor());
      textPaint.drawableState = getDrawableState();

      canvas.save();

      if (topDown) {
          canvas.translate(getWidth(), 0);
          canvas.rotate(90);
      } else {
          canvas.translate(0, getHeight());
          canvas.rotate(-90);
      }

      canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());

      getLayout().draw(canvas);
      canvas.restore();
  }

}
  • 默认情况下,旋转的文本是从上到下。
    如果我们设置" android:gravity =" bottom"",那么它是从下往上绘制的。
    我们将旋转文本的状态(从上到下/从下到上)保存在布尔变量" topDown"中。

  • 在" onMeasure()"方法中,我们交换宽度和高度以绘制旋转的文本。

  • 最后,在基于topDown布尔标志的onDraw()方法中,我们根据重力设置应用旋转。

更进一步,让我们使用百分比布局支持和Vertical TextView编写有趣的登录UI概念代码。

Android百分比布局和垂直TextView项目结构

记下" anim"文件夹中的xml文件。
它们将用于在登录之间设置动画,并注册布局和按钮。

Android百分比布局和垂直TextView代码

在build.gradle文件中添加以下依赖项。

compile 'com.android.support:percent:25.3.1'

下面给出了" activity_main.xml"的xml布局代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  android:id="@+id/viewGroup"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <ImageView
      android:id="@+id/background"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_alignParentBottom="true"
      android:scaleType="centerCrop"
      android:src="@drawable/background" 

  <android.support.percent.PercentRelativeLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:background="@color/colorAccentTrans"
      android:orientation="horizontal">

      <LinearLayout
          android:id="@+id/llSign_in"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:layout_alignParentLeft="true"
          android:orientation="horizontal"
          app:layout_widthPercent="85%">

          <com.theitroad.verticaltextviewandpercentlayout.VerticalTextView
              android:id="@+id/txtSignIn"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center"
              android:paddingTop="15dp"
              android:rotation="180"
              android:text="@string/sign_in"
              android:textAllCaps="true"
              android:textColor="#FFFFFF"
              android:textSize="26sp"
              android:visibility="gone" 

          <include
              layout="@layout/layout_sign_in"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center" 
      </LinearLayout>

      <LinearLayout
          android:id="@+id/llRegister"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:layout_alignParentRight="true"
          android:layout_alignParentEnd="true"
          android:background="@color/colorYTrans"
          android:orientation="horizontal"
          app:layout_widthPercent="15%">

          <com.theitroad.verticaltextviewandpercentlayout.VerticalTextView
              android:id="@+id/txtRegister"
              android:layout_width="wrap_content"
              android:layout_height="match_parent"
              android:layout_gravity="center"
              android:gravity="center"
              android:paddingTop="15dp"
              android:rotation="180"
              android:text="@string/register"
              android:textAllCaps="true"
              android:textColor="#FFFFFF"
              android:textSize="26sp"
              android:visibility="visible" 

          <include
              layout="@layout/layout_register"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center" 

      </LinearLayout>
  </android.support.percent.PercentRelativeLayout>

</RelativeLayout>

注意上面代码中指定的百分比。

首先,让" layout_sign_in.xml"占据屏幕的大部分。
此外,我们还为登录隐藏了" VerticalTextView"。
最终,当放置" layout_register.xml"屏幕时,这些事情将被颠倒。

下面给出了layout_sign_in.xml的xml布局代码。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center"
      android:orientation="vertical"
      android:padding="24dp">

      <EditText
          android:id="@+id/inEmail"
          android:layout_width="match_parent"
          android:layout_height="48dip"
          android:background="@drawable/input_field"
          android:hint="@string/email"
          android:imeOptions="actionNext"
          android:inputType="textEmailAddress"
          android:maxLines="1"
          android:paddingLeft="16.0dip"
          android:paddingRight="16.0dip"
          android:textColor="#FFF"
          android:textColorHint="#b3ffffff"
          android:textCursorDrawable="@null" 

      <EditText
          android:id="@+id/inPassword"
          android:layout_width="match_parent"
          android:layout_height="48dip"
          android:layout_marginTop="@dimen/activity_horizontal_margin"
          android:background="@drawable/input_field"
          android:hint="@string/password"
          android:imeOptions="actionDone"
          android:inputType="textPassword"
          android:maxLines="1"
          android:paddingLeft="16.0dip"
          android:paddingRight="16.0dip"
          android:textColor="#FFF"
          android:textColorHint="#b3ffffff"
          android:textCursorDrawable="@null" 

      <Button
          android:id="@+id/btnSignIn"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_marginTop="20dp"
          android:background="@null"
          android:text="@string/sign_in"
          android:textColor="#FFF"
          android:textSize="28sp"
          android:textStyle="bold" 

      <Button
          android:id="@+id/btnForgotPassword"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_marginBottom="10dp"
          android:background="@android:color/transparent"
          android:focusable="true"
          android:gravity="center"
          android:text="@string/forgot_password"
          android:textColor="#FFF"
          android:textSize="16sp" 

  </LinearLayout>

</RelativeLayout>

下面给出了layout_register.xml的xml布局代码。

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <ScrollView
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:fillViewport="true">

      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:gravity="center"
          android:orientation="vertical"
          android:padding="24dp">

          <EditText
              android:id="@+id/inFirstName"
              android:layout_width="match_parent"
              android:layout_height="48dip"
              android:background="@drawable/input_field"
              android:focusable="true"
              android:focusableInTouchMode="true"
              android:hint="@string/first_name"
              android:imeOptions="actionNext"
              android:inputType="text"
              android:maxLines="1"
              android:paddingLeft="16.0dip"
              android:paddingRight="16.0dip"
              android:textColor="#FFF"
              android:textColorHint="#b3ffffff"
              android:textCursorDrawable="@null" 

          <EditText
              android:id="@+id/inLastName"
              android:layout_width="match_parent"
              android:layout_height="48dip"
              android:layout_marginTop="@dimen/activity_vertical_margin"
              android:background="@drawable/input_field"
              android:focusable="true"
              android:focusableInTouchMode="true"
              android:hint="@string/last_name"
              android:imeOptions="actionNext"
              android:maxLines="1"
              android:paddingLeft="16.0dip"
              android:paddingRight="16.0dip"
              android:textColor="#FFF"
              android:textColorHint="#b3ffffff"
              android:textCursorDrawable="@null" 

          <EditText
              android:id="@+id/inEmail"
              android:layout_width="match_parent"
              android:layout_height="48dip"
              android:layout_marginTop="@dimen/activity_vertical_margin"
              android:background="@drawable/input_field"
              android:focusable="true"
              android:focusableInTouchMode="true"
              android:hint="@string/email"
              android:imeOptions="actionNext"
              android:inputType="textEmailAddress"
              android:maxLines="1"
              android:paddingLeft="16.0dip"
              android:paddingRight="16.0dip"
              android:textColor="#FFF"
              android:textColorHint="#b3ffffff"
              android:textCursorDrawable="@null" 

          <EditText
              android:id="@+id/inPassword"
              android:layout_width="match_parent"
              android:layout_height="48dip"
              android:layout_marginTop="@dimen/activity_vertical_margin"
              android:background="@drawable/input_field"
              android:focusable="true"
              android:focusableInTouchMode="true"
              android:hint="@string/password"
              android:imeOptions="actionNext"
              android:inputType="textPassword"
              android:maxLines="1"
              android:paddingLeft="16.0dip"
              android:paddingRight="16.0dip"
              android:textColor="#FFF"
              android:textColorHint="#b3ffffff"
              android:textCursorDrawable="@null" 

          <EditText
              android:id="@+id/inConfirmPassword"
              android:layout_width="match_parent"
              android:layout_height="48dip"
              android:layout_marginTop="@dimen/activity_vertical_margin"
              android:background="@drawable/input_field"
              android:focusable="true"
              android:focusableInTouchMode="true"
              android:fontFamily="sans-serif-light"
              android:hint="@string/confirm_password"
              android:imeOptions="actionNext"
              android:inputType="textPassword"
              android:maxLines="1"
              android:paddingLeft="16.0dip"
              android:paddingRight="16.0dip"
              android:textColor="#FFF"
              android:textColorHint="#b3ffffff"
              android:textCursorDrawable="@null" 

          <EditText
              android:id="@+id/inPhone"
              android:layout_width="match_parent"
              android:layout_height="48dip"
              android:layout_marginTop="@dimen/activity_vertical_margin"
              android:background="@drawable/input_field"
              android:focusable="true"
              android:focusableInTouchMode="true"
              android:hint="@string/phone"
              android:imeOptions="actionNext"
              android:inputType="phone"
              android:maxLines="1"
              android:paddingLeft="16.0dip"
              android:paddingRight="16.0dip"
              android:textColor="#FFF"
              android:textColorHint="#b3ffffff"
              android:textCursorDrawable="@null" 

          <Button
              android:id="@+id/btnRegister"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_marginTop="20dp"
              android:background="@null"
              android:text="@string/register"
              android:textColor="#FFF"
              android:textSize="28sp"
              android:textStyle="bold" 

      </LinearLayout>

  </ScrollView>

</RelativeLayout>

另外,每个EditText的背景都在文件shape.xml中的drawable文件夹下定义,如下所示。

<?xml version="1.0" encoding="utf-8"?>
<shape
  xmlns:android="https://schemas.android.com/apk/res/android"
  android:shape="rectangle">
  <solid android:color="#1affffff"
  <corners android:radius="2.0dip"
</shape>

下面给出了MainActivity.java的代码。

package com.theitroad.verticaltextviewandpercentlayout;

import android.support.percent.PercentLayoutHelper;
import android.support.percent.PercentRelativeLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

  VerticalTextView txtSignIn, txtRegister;
  LinearLayout llSignIn, llRegister;
  Button btnRegister, btnSignIn;

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

      llSignIn = (LinearLayout) findViewById(R.id.llSign_in);
      llRegister = (LinearLayout) findViewById(R.id.llRegister);

      txtRegister = (VerticalTextView) findViewById(R.id.txtRegister);
      txtSignIn = (VerticalTextView) findViewById(R.id.txtSignIn);

      btnSignIn = (Button) findViewById(R.id.btnSignIn);
      btnRegister = (Button) findViewById(R.id.btnRegister);

      txtSignIn.setOnClickListener(this);
      txtRegister.setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {
      switch (v.getId()) {
          case R.id.txtSignIn:
              hideSoftKeyBoard();
              showSignInForm();
              break;
          case R.id.txtRegister:
              hideSoftKeyBoard();
              showRegisterForm();
              break;
      }
  }

  private void showSignInForm() {
      PercentRelativeLayout.LayoutParams paramsLogin = (PercentRelativeLayout.LayoutParams) llRegister.getLayoutParams();
      PercentLayoutHelper.PercentLayoutInfo infoLogin = paramsLogin.getPercentLayoutInfo();
      infoLogin.widthPercent = 0.15f;
      llRegister.requestLayout();

      PercentRelativeLayout.LayoutParams paramsSignup = (PercentRelativeLayout.LayoutParams) llSignIn.getLayoutParams();
      PercentLayoutHelper.PercentLayoutInfo infoSignup = paramsSignup.getPercentLayoutInfo();
      infoSignup.widthPercent = 0.85f;
      llSignIn.requestLayout();

      txtRegister.setVisibility(View.VISIBLE);
      txtSignIn.setVisibility(View.GONE);
      Animation translate = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.translate_left_to_right);
      llSignIn.startAnimation(translate);

      Animation clockwise = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.rotate_left_to_right);
      btnSignIn.startAnimation(clockwise);

  }

  private void showRegisterForm() {
      PercentRelativeLayout.LayoutParams paramsLogin = (PercentRelativeLayout.LayoutParams) llSignIn.getLayoutParams();
      PercentLayoutHelper.PercentLayoutInfo infoLogin = paramsLogin.getPercentLayoutInfo();
      infoLogin.widthPercent = 0.15f;
      llSignIn.requestLayout();

      PercentRelativeLayout.LayoutParams paramsSignup = (PercentRelativeLayout.LayoutParams) llRegister.getLayoutParams();
      PercentLayoutHelper.PercentLayoutInfo infoSignup = paramsSignup.getPercentLayoutInfo();
      infoSignup.widthPercent = 0.85f;
      llRegister.requestLayout();

      txtRegister.setVisibility(View.GONE);
      txtSignIn.setVisibility(View.VISIBLE);
      Animation translate = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.translate_right_to_left);
      llRegister.startAnimation(translate);

      Animation clockwise = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.rotate_right_to_left);
      btnRegister.startAnimation(clockwise);

  }

  private void hideSoftKeyBoard() {
      InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);

      if (imm.isAcceptingText()) { 
          //verify if the soft keyboard is open
          imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
      }
  }
}

从上面的代码得出的推论很少是:

  • 我们交换在PercentRelativeLayout内部保存的LinearLayouts的百分比宽度(使用浮点值),即layout_sign_in和layout_register。

  • 除此之外,我们还为上述布局设置了动画,并显示了从" VerticalTextView"到其相应Button的过渡。

  • 每次单击" VerticalTextView"时都会调用" hideSoftKeyboard()",以关闭任何先前打开的键盘。

注意:要在应用程序启动时隐藏键盘,我们将AndroidManifest.xml文件中的" windowSoftInputMode"设置为" hidden",如下所示。

<activity
          android:name=".MainActivity"
          android:windowSoftInputMode="stateHidden">