最近在看一款新闻类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已经成功改变了,我们就不必要考虑太多的事件因素,完全可以掌控了
写的不好请大家见解。