您的位置:首页 > 移动开发 > Android开发

android view放大被遮挡,我来解决

2016-11-23 09:34 686 查看


     首先 先来说说这个问题出现时的样式吧(如图1)。因为在做android TV应用开发时, 很经常用到在控件获取焦点时,采用控件放大的动画效果,来增加用户的聚焦和体验。这时大家就想到直接让焦点控件执行放大动画,不就可以吗。 但是当你直接这个做得时候,一个大问题就来了(如图1),你会发现 放大的控件可以覆盖左上的控件, 但是会被右下的控件覆盖(前提是你所加入控件的顺序从左到右,从上到下的。 本质是前加的控件放大后会被后加的控件覆盖)。

    上段文字已经提出了问题,  现在来分析一下这个问题。 为什么会出现呢? 以LinearLayout为例(RelativeLayout 大家不要着急,我在文章的后面会给出说明),线性布局在添加子View/子ViewGroup时,是按照添加的先后顺序进行加入的, 这时当你放大(非最后一个控件)控件时,这个被放大控件的区域达到其他控件所占有的区域时, 这个时候因为后加入的控件的Z轴值 比放大控件的大,所以放大的控件会被后加入的控件所覆盖。反正比放大控件先加的控件Z轴值小,就不会覆盖放大控件。 前面出现的Z轴,
这里解释一下,我们看到的屏幕宽,高分别表示X,Y轴,和屏幕垂直轴 称为Z轴。

   现在到了解决问题的时候了。经过分析, 我们发现跟Z轴值的大小有关,而且还发现Z轴的大小跟控件加入group的先后顺序是有关系的, 先加入的小于后加入的。 这时有些人就会想到View.bringToFront();这个方法, 这个方法的意思是把view至于同级控件的最上方,但是不会超越父控件。该方法在某些简单的布局中,或者不需要刷新的布局中可以使用,并且也有效果。 但是在稍微复杂的或者需要刷新的界面 就会出现错乱的问题。  既然有这样一个方法,虽然会出现问题, 但是我们也要去看看 这个方法为什么可以达到一定的效果。

代码分析:

在view中调用bringToFront, 其实源码中的实现为

public void bringToFront() {
if (mParen
4000
t != null) {
mParent.bringChildToFront(this);
}
}

我们继续看方法

mParent.bringChildToFront(this);

/**
* {@inheritDoc}
*/
public void bringChildToFront(View child) {
//获取该调用的childView是父控件的第几子
final int index = indexOfChild(child);
if (index >= 0) {
//在父控件的view数组中移除
removeFromArray(index);
//添加到父控件中view数组的最后面
addInArray(child, mChildrenCount);
child.mParent = this;
requestLayout();
//重新绘制, 这个时候就会按照父控件中的view数组重新绘制,这个时候child就变成最后绘制了。
invalidate();
}
}

看到这里,大家应该明白为什么当你调用View.bringToFront()方法时  会有一定的效果了吧。

但是在复杂的UI或者UI需要经常刷新的时候, 单单靠这个源生的方法是无法满足的, 经过研究 发现 在viewgroup绘制子view的时候 会调用方法

getChildDrawingOrder

大家可以看看getChildDrawingOrder这个方法的解释

/ **

      *返回要为此迭代绘制的子元素的索引。 覆盖此

      *如果你想改变孩子的绘画顺序。 默认情况下,它

      *返回i。

      * <p>

      *注意:为了调用此方法,您必须启用子订单

      *首先通过调用{@link #setChildrenDrawingOrderEnabled(boolean)}。

      *:

      * @param i当前迭代。

      * @return孩子的索引来绘制这个迭代。

      *:

      * @see #setChildrenDrawingOrderEnabled(boolean)

      * @see #isChildrenDrawingOrderEnabled()

      * /

好了,看到这个方法我们就知道 可以通过改变这个方法的返回值 来修改绘制的顺序了(具体的有兴趣的读者 可以去查看一下getChildDrawingOrder 方法在ViewGroup中的调用情况)。

好了,给大家分析了这个多, 接着我就直接点 上代码了, 注释已经写好。 有疑问的可以留言,必回。

 代码结构:

package com.example.testviewbringtofront;

import android.view.View;

import android.view.ViewGroup;

public class ControlViewBringToFront {

 private int mFocusChildIndex;

 

 public ControlViewBringToFront(){

  

 }

 

 public ControlViewBringToFront(ViewGroup vg){

  //设置这个方法后, 子view可以绘制在父控件的padding区域之上, 否则绘制在padding区域之下

  vg.setClipChildren(false);

  vg.setClipToPadding(false);

 }

 

 public void bringChildToFront(ViewGroup viewGroup, View childView){

  mFocusChildIndex = viewGroup.indexOfChild(childView);

  if(mFocusChildIndex != -1){

   viewGroup.postInvalidate();

  }

 }

 

 /**

  * 此函数 dispatchDraw 中调用. <br>

  * 原理就是和最后一个要绘制的view,交换了位置. <br>

  * 因为dispatchDraw最后一个绘制的view是在最上层的. <br>

  * 这样就避免了使用 bringToFront 导致焦点错乱问题. <br>

  */

 public int getChildDrawingOrder(int childCount, int i){

  if(mFocusChildIndex != -1){

  

   if(i == childCount-1){

    if(mFocusChildIndex > childCount-1){

     mFocusChildIndex = childCount-1;

    }

    return mFocusChildIndex;

   }

   

   if(i == mFocusChildIndex){

    

    return childCount -1;

   }

  

  }

  if(childCount <= i){

   i = childCount-1;

  }

  return i;

 }

 

 

}

重写的ViewGroup,以LinearLayout 为例:

package com.example.testviewbringtofront.view;

import com.example.testviewbringtofront.ControlViewBringToFront;

import android.content.Context;

import android.util.AttributeSet;

import android.view.View;

import android.widget.LinearLayout;

public class MyLinearLayout extends LinearLayout{

 private ControlViewBringToFront mControlViewBringToFront;

 public MyLinearLayout(Context context, AttributeSet attrs) {

  super(context, attrs);

  // TODO Auto-generated constructor stub

  //getChildDrawingOrder方法要求这个方法要设置成true

  setChildrenDrawingOrderEnabled(true);

  mControlViewBringToFront = new ControlViewBringToFront(this);

 }

 

 @Override

 protected int getChildDrawingOrder(int childCount, int i) {

  // TODO Auto-generated method stub

//  return super.getChildDrawingOrder(childCount, i);

  return mControlViewBringToFront.getChildDrawingOrder(childCount, i);

 }

 

 @Override

 public void bringChildToFront(View child) {

  // TODO Auto-generated method stub

//  super.bringChildToFront(child);

  mControlViewBringToFront.bringChildToFront(this, child);

 }

}

主类:

package com.example.testviewbringtofront;

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnFocusChangeListener;

import android.widget.Button;

public class MainActivity extends Activity implements OnFocusChangeListener{

 @Override

 protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);

  initView();

 }

 private void initView() {

  // TODO Auto-generated method stub

  Button button1 = (Button)findViewById(R.id.button1);

  Button button2 = (Button)findViewById(R.id.button2);

  Button button3 = (Button)findViewById(R.id.button3);

  Button button4 = (Button)findViewById(R.id.button4);

  Button button5 = (Button)findViewById(R.id.button5);

  Button button6 = (Button)findViewById(R.id.button6);

  Button button7 = (Button)findViewById(R.id.button7);

  Button button8 = (Button)findViewById(R.id.button8);

  Button button9 = (Button)findViewById(R.id.button9);

  button1.setOnFocusChangeListener(this);

  button2.setOnFocusChangeListener(this);

  button3.setOnFocusChangeListener(this);

  button4.setOnFocusChangeListener(this);

  button5.setOnFocusChangeListener(this);

  button6.setOnFocusChangeListener(this);

  button7.setOnFocusChangeListener(this);

  button8.setOnFocusChangeListener(this);

  button9.setOnFocusChangeListener(this);

 }

 @Override

 public void onFocusChange(View v, boolean hasFocus) {

  // TODO Auto-generated method stub

  switch (v.getId()) {

  case R.id.button7:

  case R.id.button8:

  case R.id.button9:

   if(hasFocus){

    v.animate().scaleX(2.2f).scaleY(2.2f).setDuration(500).start();

//    v.bringToFront();

   }else{

    v.animate().scaleX(1.0f).scaleY(1.0f).setDuration(500).start();  

   }

   break;

  default:

   if(hasFocus){

    v.animate().scaleX(2.2f).scaleY(2.2f).setDuration(500).start();

    v.bringToFront();

   }else{

    v.animate().scaleX(1.0f).scaleY(1.0f).setDuration(500).start();  

   }

   break;

  }

  

 }

}

使用到的布局文件XML:

<LinearLayout 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:orientation="vertical" >

    <com.example.testviewbringtofront.view.MyLinearLayout

        android:layout_width="match_parent"

        android:layout_height="200dp"

        android:gravity="center_vertical|center_horizontal"

        android:orientation="horizontal"

         >

  <TextView

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:layout_marginRight="25dp"

      android:text="使用重写后的Layout,在调用bringToFront,执行放大动画"/>

        <Button

            android:id="@+id/button1"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginRight="15dp"

            android:background="@android:color/holo_red_light"

            android:text="Button1" />

        <Button

            android:id="@+id/button2"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginRight="15dp"

            android:background="@android:color/holo_green_dark"

            android:text="Button2" />

        <Button

            android:id="@+id/button3"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginRight="15dp"

            android:background="@android:color/holo_blue_bright"

            android:text="Button3" />

    </com.example.testviewbringtofront.view.MyLinearLayout>

    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="200dp"

        android:gravity="center_vertical|center_horizontal"

        android:orientation="horizontal" >

  <TextView

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:layout_marginRight="25dp"

      android:text="直接调用bringToFront,执行放大动画"/>

        <Button

            android:id="@+id/button4"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginRight="15dp"

            android:background="@android:color/holo_red_light"

            android:text="Button4" />

        <Button

            android:id="@+id/button5"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginRight="15dp"

            android:background="@android:color/holo_green_dark"

            android:text="Button5" />

        <Button

            android:id="@+id/button6"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginRight="15dp"

            android:background="@android:color/holo_blue_bright"

            android:text="Button6" />

    </LinearLayout>

   

    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="200dp"

        android:gravity="center_vertical|center_horizontal"

        android:orientation="horizontal" >

  <TextView

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:layout_marginRight="25dp"

      android:text="直接执行放大动画"/>

        <Button

            android:id="@+id/button7"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginRight="15dp"

            android:background="@android:color/holo_red_light"

            android:text="Button7" />

        <Button

            android:id="@+id/button8"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginRight="15dp"

            android:background="@android:color/holo_green_dark"

            android:text="Button8" />

        <Button

            android:id="@+id/button9"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginRight="15dp"

            android:background="@android:color/holo_blue_bright"

            android:text="Button9" />

    </LinearLayout>

</LinearLayout&g
ae11
t;

资源下载地址  http://download.csdn.net/detail/a22422931/9699529




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: