Android ViewTree and DecorView

       最近在看一款新闻类APP的源码,进行了一翻学习,感觉学到了不少东西,给大家分享一下,说的不好,请大家见谅。这款新闻类的APP采用多个Fragment实现的主界面的展示,而且界面中存在了界面缩放、位移、透明度等动画效果!所以对事件分发的处理比较繁琐,作者处理的方式是改变了ViewTree的结构,自定义了两个ViewGroup加到DecorView的下面,Android ViewTree视图的最顶层的View是DecorView,

我们通过activity.getWindow().getDecorView()可以获得DecorView的对象

先来看一张原始的ViewTree图片

可以看到DecorView下方直接对应的是一个LinearLayout,我们在对ViewTree做一下改变,直接看核心代码

public class ResideMenu extends FrameLayout{    

    private ImageView imageViewShadow;
    private ImageView imageViewBackground;
    private LinearLayout layoutLeftMenu;
    private LinearLayout layoutRightMenu;
    private ScrollView scrollViewLeftMenu;
    private ScrollView scrollViewRightMenu;
    private ScrollView scrollViewMenu;
    /** Current attaching activity. */
    private Activity activity;
    /** The DecorView of current activity. */
    private ViewGroup viewDecor;
    private TouchDisableView viewActivity;
    /** The flag of menu opening status. */
    private boolean isOpened;
    private float shadowAdjustScaleX;
    private float shadowAdjustScaleY;
    /** Views which need stop to intercept touch events. */
    private List<View> ignoredViews;
    private List<ResideMenuItem> leftMenuItems;
    private List<ResideMenuItem> rightMenuItems;
    private DisplayMetrics displayMetrics = new DisplayMetrics();
    private OnMenuListener menuListener;
    private float lastRawX;
    private boolean isInIgnoredView = false;
    private int scaleDirection = DIRECTION_LEFT;
    private int pressedState   = PRESSED_DOWN;
    private List<Integer> disabledSwipeDirection = new ArrayList<Integer>();
    // Valid scale factor is between 0.0f and 1.0f.
    private float mScaleValue = 0.5f;


    public ResideMenu(Context context) {
        super(context);
        initViews(context);
    }


    private void initViews(Context context){
        LayoutInflater inflater = (LayoutInflater)
                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.residemenu, this);
        scrollViewLeftMenu = (ScrollView) findViewById(R.id.sv_left_menu);
        scrollViewRightMenu = (ScrollView) findViewById(R.id.sv_right_menu);
        imageViewShadow = (ImageView) findViewById(R.id.iv_shadow);
        layoutLeftMenu = (LinearLayout) findViewById(R.id.layout_left_menu);
        layoutRightMenu = (LinearLayout) findViewById(R.id.layout_right_menu);
        imageViewBackground = (ImageView) findViewById(R.id.iv_background);
    }


    @Override
    protected boolean fitSystemWindows(Rect insets) {
        // Applies the content insets to the view's padding, consuming that content (modifying the insets to be 0),
        // and returning true. This behavior is off by default and can be enabled through setFitsSystemWindows(boolean)
        // in api14+ devices.
        this.setPadding(viewActivity.getPaddingLeft() + insets.left, viewActivity.getPaddingTop() + insets.top,
                viewActivity.getPaddingRight() + insets.right, viewActivity.getPaddingBottom() + insets.bottom);
        insets.left = insets.top = insets.right = insets.bottom = 0;
        return true;
    }


    /**
     * Set up the activity;
     *
     * @param activity
     */
    public void attachToActivity(Activity activity){
        initValue(activity);
        setShadowAdjustScaleXByOrientation();
        viewDecor.addView(this, 0);
    }


    private void initValue(Activity activity){
        this.activity   = activity;
        leftMenuItems   = new ArrayList<ResideMenuItem>();
        rightMenuItems  = new ArrayList<ResideMenuItem>();
        ignoredViews    = new ArrayList<View>();
        viewDecor = (ViewGroup) activity.getWindow().getDecorView();
        viewActivity = new TouchDisableView(this.activity);


        View mContent   = viewDecor.getChildAt(0);//得到对象
        viewDecor.removeViewAt(0);//移除第一个位置的对象
        viewActivity.setContent(mContent);//交给自己来处理       
        addView(viewActivity);//改写了ViewTree结构


        ViewGroup parent = (ViewGroup) scrollViewLeftMenu.getParent();
        parent.removeView(scrollViewLeftMenu);
        parent.removeView(scrollViewRightMenu);
    }


我们看到,将自定义的ViewGroup(FrameLayout)成功的加入到了ViewTree的结构中,viewActivity是一个自定义ViewGroup,里面做一些事件的处理


class TouchDisableView extends ViewGroup {


    private View mContent;


    // private int mMode;
    private boolean mTouchDisabled = false;


    public TouchDisableView(Context context) {
        this(context, null);
    }


    public TouchDisableView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    public void setContent(View v) {
        if (mContent != null) {
            this.removeView(mContent);
        }
        mContent = v;
        addView(mContent);
    }


    public View getContent() {
        return mContent;
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {


        int width = getDefaultSize(0, widthMeasureSpec);
        int height = getDefaultSize(0, heightMeasureSpec);
        setMeasuredDimension(width, height);


        final int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width);
        final int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0, height);
        mContent.measure(contentWidth, contentHeight);
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int width = r - l;
        final int height = b - t;
        mContent.layout(0, 0, width, height);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mTouchDisabled;
    }


    void setTouchDisable(boolean disableTouch) {
        mTouchDisabled = disableTouch;
    }


    boolean isTouchDisabled() {
        return mTouchDisabled;
    }


我们再来看一下改变后的ViewTree结构

可以看到,ViewTree已经成功改变了,我们就不必要考虑太多的事件因素,完全可以掌控了

写的不好请大家见解。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值