android view层次与位置大小

1、改变层次

首先要明白,android的层次由摆放view的先后顺序决定,也就是addView中的index,0表示最下面,越大越上面,不会超过容器的包含的View个数,(因为是数组下标)。

1、所以需要第一种方法,是最原始的方法。将一个view remove掉然后再加入进来,因为越后面加入的view,在越下面。

如下代码展示了如何交换两个ImageView的层次。

                int screen_w = getResources().getDisplayMetrics().widthPixels;
                int screen_h = getResources().getDisplayMetrics().heightPixels;
                mContent.removeAllViews();
                RelativeLayout.LayoutParams layoutParams1 = (RelativeLayout.LayoutParams) mExample1.getLayoutParams();
                RelativeLayout.LayoutParams layoutParams2 = (RelativeLayout.LayoutParams) mExample2.getLayoutParams();
                mExample1 = new ImageView(MainActivity.this);
                mExample2 = new ImageView(MainActivity.this);
                mExample1.setImageResource(R.drawable.example_h);
                mExample2.setImageResource(R.drawable.example_v);
                layout(layoutParams1, layoutParams2);
                if (mExample2OnTop) {
                    layoutParams1.width = screen_w / 4;
                    layoutParams1.height = screen_h / 4;

                    layoutParams2.width = screen_w;
                    layoutParams2.height = screen_h;

                    mExample1.setLayoutParams(layoutParams1);
                    mExample2.setLayoutParams(layoutParams2);

                    mContent.addView(mExample2);
                    mContent.addView(mExample1);

                    mExample2OnTop = false;
                } else {
                    layoutParams1.width = screen_w;
                    layoutParams1.height = screen_h;

                    layoutParams2.width = screen_w / 4;
                    layoutParams2.height = screen_h / 4;

                    mExample1.setLayoutParams(layoutParams1);
                    mExample2.setLayoutParams(layoutParams2);

                    mContent.addView(mExample1);
                    mContent.addView(mExample2);

                    mExample2OnTop = true;
                }

                mExample2.setOnClickListener(ImageSwitchListener);
                mExample1.setOnClickListener(ImageSwitchListener);

mContent为父容器,先用removeAllViews将所有view去除,然后使用addView将View再添加,注意在if和else里面 添加两个View的顺序。layoutParam为位置view大小的方法,在实验中,楼主遇到一个问题,就是重新添加后两个View不能点击,换成Button发现不是状态的问题,完全没有点击效果,只有按Home键退出后,View才会响应OnClick事件,但是重新添加后又不能点击,重新New一个就OK了,怀疑是remove后是不是有些私有状态不对了。只有OnResume之后,恢复了过来,楼主没有深入研究,所以就新建了一下,重新设置参数。也算规避掉了,望知情人士提供线索。这种方法实际应用意义不大,又要重新new,又要remove和add。开销蛮大的。

楼主后来想了下,可能后AttachWindow的原因比较大,onResume之后重新AttachWindow所以按键效果就出来了。

于是介绍下一种方法 bringToFront()
                int screen_w = getResources().getDisplayMetrics().widthPixels;
                int screen_h = getResources().getDisplayMetrics().heightPixels;
                RelativeLayout.LayoutParams layoutParams1 = (RelativeLayout.LayoutParams) mExample1.getLayoutParams();
                RelativeLayout.LayoutParams layoutParams2 = (RelativeLayout.LayoutParams) mExample2.getLayoutParams();
                layout(layoutParams1, layoutParams2);
                mContent.requestLayout();
                if (mExample2OnTop) {
                    layoutParams1.width = screen_w / 4;
                    layoutParams1.height = screen_h / 4;

                    layoutParams2.width = screen_w;
                    layoutParams2.height = screen_h;

                    mExample1.setLayoutParams(layoutParams1);
                    mExample2.setLayoutParams(layoutParams2);

                    mExample1.bringToFront();

                    mExample2OnTop = false;
                } else {
                    layoutParams1.width = screen_w;
                    layoutParams1.height = screen_h;

                    layoutParams2.width = screen_w / 4;
                    layoutParams2.height = screen_h / 4;

                    mExample1.setLayoutParams(layoutParams1);
                    mExample2.setLayoutParams(layoutParams2);

                    mExample2.bringToFront();

                    mExample2OnTop = true;
                }
bringToFront起到了相同的作用,因为bringToFront将view的index设置为最大,内部只是调整了view结构树的层次,而不是remove和add。减小了开销。是目前比较常用的方法

也许有人会用到,bringToFront之后再重新调整到原来位置,这里提供一份代码。
private void moveToBack(View currentView) {
    ViewGroup viewGroup = ((ViewGroup) currentView.getParent());
    int index = viewGroup.indexOfChild(currentView);
    for(int i = 0; i<index; i++) {
        viewGroup.bringChildToFront(viewGroup.getChildAt(i));
    }
}



3、在android5.0 api引入一个setZ(float)的函数,也可以调整view的层次。听说原理是相当于修改translationZ的属性(就是在3.0还是4.0引入的RotateXY,ScaleXY,TranslationXY之类的属性。)。全部代码不贴了,只看关键代码
                if (mExample2OnTop) {
                //                    mExample1.bringToFront();
                    mExample1.setZ(100.f);
                    mExample2.setZ(0.f);
                    mExample2OnTop = false;
                } else {
//                    mExample2.bringToFront();
                    mExample1.setZ(0.f);
                    mExample2.setZ(100.f);

                    mExample2OnTop = true;
                }
这个接口比较新。作用是体现出来了。但是副作用还不知道。


2、在代码中动态调整view的大小。
大部分情况下,View的大小在xml中已经定好了,不会在运行中动态调整,但是万一遇到一些需求需要在运行中调整view的大小呢
这个比层次简单,基本上就是修改 LayoutParams

不过需要注意的是,需要注意到父容器是什么类型的,FrameLayout,LinearLayout,RelativeLayout等,因为不同类型的LayoutParams是不同的

</pre><pre class="java" name="code">    private void layout(RelativeLayout.LayoutParams layoutParams1, RelativeLayout.LayoutParams layoutParams2) {
        layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
        layoutParams2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        layoutParams2.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    }
请看,上面一些属性是只有RelativeLayout才有的。所以这就是为什么要区分父容器类型的原因。


下面是如何修改View大小的代码

                    RelativeLayout.LayoutParams layoutParams1 = (RelativeLayout.LayoutParams) mExample1.getLayoutParams();
                    RelativeLayout.LayoutParams layoutParams2 = (RelativeLayout.LayoutParams) mExample2.getLayoutParams();
                    
                    layoutParams1.width = screen_w / 4;
                    layoutParams1.height = screen_h / 4;

                    layoutParams2.width = screen_w;
                    layoutParams2.height = screen_h;

                    mExample1.setLayoutParams(layoutParams1);
                    mExample2.setLayoutParams(layoutParams2);

这样就好了,连invalidate或者requestLayout都不需要调用。因为内部自己会调用。
题外话,如果需要addView的话,那么使用getLayoutParams是没用的,因为这个你自己新建的一个View,没有与父容器有任何关联。所以LayoutParams也需要你自己创建。
        mExample1 = new Button(this);
        mExample2 = new Button(this);

        RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(screen_w, screen_h);
        RelativeLayout.LayoutParams layoutParams2 = new RelativeLayout.LayoutParams(screen_w / 4, screen_h / 4);

        layout(layoutParams1, layoutParams2);

        mExample1.setLayoutParams(layoutParams1);
        mExample2.setLayoutParams(layoutParams2);

        mContent.addView(mExample1);
        mContent.addView(mExample2);






你可能感兴趣的:(android)