一 自定义DrawerLayout设置背景和item动画效果
1 效果图
2 原理
- 自定义MyDrawSlideBar继承LinearLayout作为侧拉栏
- 自定义MyDrawerLayout从而获取对应的侧拉栏SlideBar,偷梁换柱:移除SlideBar添加一个自定义的RelativeLayout,再将一个要显示的背景View和SlideBar添加到RelativeLayout中去
- 背景View通过MyDrawerLayout获取移动要素,绘制背景(贝塞尔曲线),当设置背景为图片时,使用paint的Shader实现
- MyDrawSlideBar获取移动要素,计算出每个child的平移距离,实现动画效果
3 主要代码
MyDrawerLayout
public class MyDrawerLayout extends DrawerLayout implements DrawerLayout.DrawerListener {
//背景 自定义控件
private MyDrawBgRealativeLayout myDrawBgRealativeLayout;
//含有 布局内容的 Linealayout自定义控件
private MyDrawSlideBar myDrawSlideBar;
private float y;
private float slideOffset;
//内容区域
private View contenView;
public MyDrawerLayout(Context context) {
super(context);
}
public MyDrawerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
initChild();
}
private void initChild() {
for(int i=0;i<getChildCount();i++) {
View view = getChildAt(i);
if (view instanceof MyDrawSlideBar) {
myDrawSlideBar= (MyDrawSlideBar) view;
break;
}else {
contenView=view;
}
}
//移除子控件 因为不符合我们的需求
removeView(myDrawSlideBar);
myDrawBgRealativeLayout = new MyDrawBgRealativeLayout(myDrawSlideBar);
addView(myDrawBgRealativeLayout);
addDrawerListener(this);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP) {
closeDrawers();
myDrawBgRealativeLayout.onMotionEventUp();
return super.dispatchTouchEvent(ev);
}
y=ev.getY();
if (slideOffset < 1) {
super.dispatchTouchEvent(ev);
}else if(ev.getAction() == MotionEvent.ACTION_MOVE) {
//当大于1时 内容区域不做偏移 只是把背景贝塞尔曲线进行变化 拦截后 DrawerLayout.DrawerListener 不再起作用 因为内容不做偏移
myDrawBgRealativeLayout.setTouch(y,slideOffset);
}
return true;
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
this.slideOffset = slideOffset;
myDrawBgRealativeLayout.setTouch(y,slideOffset);
float contentViewoffset=drawerView.getWidth()*slideOffset/2;
contenView.setTranslationX(contentViewoffset);
}
@Override
public void onDrawerOpened(View drawerView) {
}
@Override
public void onDrawerClosed(View drawerView) {
}
@Override
public void onDrawerStateChanged(int newState) {
}
}
MyDrawBgRealativeLayout
public class MyDrawBgRealativeLayout extends RelativeLayout {
private MyDrawSlideBar myDrawSlideBar;
private MyDrawBgView myDrawBgView;
public MyDrawBgRealativeLayout(MyDrawSlideBar myDrawSlideBar) {
super(myDrawSlideBar.getContext() );
init(myDrawSlideBar);
}
private void init(MyDrawSlideBar myDrawSlideBar) {
//转移宽高属性
setLayoutParams(myDrawSlideBar.getLayoutParams());
int parentLayoutGravity = ((DrawerLayout.LayoutParams) getLayoutParams()).gravity;
this.myDrawSlideBar=myDrawSlideBar;
//子控件 是否居中
myDrawBgView = new MyDrawBgView(getContext());
addView( myDrawBgView, 0, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
//添加滑动内容区域
myDrawBgView.setColor(myDrawSlideBar.getBackground());
myDrawSlideBar.setBackgroundColor(Color.TRANSPARENT);
addView(myDrawSlideBar, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
public void setTouch(float y, float offset) {
//背景做贝塞尔曲线
myDrawBgView.setTouchY(y,offset);
myDrawSlideBar.setTouchY(y,offset);
}
public void onMotionEventUp() {
myDrawSlideBar.onMotionEventUp();
}
}
MyDrawBgRealativeLayout
public class MyDrawBgRealativeLayout extends RelativeLayout {
private MyDrawSlideBar myDrawSlideBar;
private MyDrawBgView myDrawBgView;
public MyDrawBgRealativeLayout(MyDrawSlideBar myDrawSlideBar) {
super(myDrawSlideBar.getContext() );
init(myDrawSlideBar);
}
private void init(MyDrawSlideBar myDrawSlideBar) {
//转移宽高属性
setLayoutParams(myDrawSlideBar.getLayoutParams());
int parentLayoutGravity = ((DrawerLayout.LayoutParams) getLayoutParams()).gravity;
this.myDrawSlideBar=myDrawSlideBar;
//子控件 是否居中
myDrawBgView = new MyDrawBgView(getContext());
addView( myDrawBgView, 0, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
//添加滑动内容区域
myDrawBgView.setColor(myDrawSlideBar.getBackground());
myDrawSlideBar.setBackgroundColor(Color.TRANSPARENT);
addView(myDrawSlideBar, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}
public void setTouch(float y, float offset) {
//背景做贝塞尔曲线
myDrawBgView.setTouchY(y,offset);
myDrawSlideBar.setTouchY(y,offset);
}
public void onMotionEventUp() {
myDrawSlideBar.onMotionEventUp();
}
}
MyDrawBgView
public class MyDrawBgView extends View {
private Paint paint;
private Path path;
private BitmapDrawable drawable;
public MyDrawBgView(Context context) {
this(context,null);
}
public MyDrawBgView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint = new Paint();
paint.setAntiAlias(true);
path = new Path();
}
public void setTouchY(float y, float percent) {
path.reset();
float width=getWidth()*percent;
float height=getHeight();
float firstPointX=width/2;
float offsetY=height/8;
path.lineTo(firstPointX,-offsetY);
path.quadTo(width * 3 / 2, y, firstPointX, height + offsetY);
path.lineTo(0, height);
path.close();
path.offset(getWidth() - width, 0);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
//完成图片的绘制
if (drawable != null) {
Bitmap bitmap=drawable.getBitmap();
Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
}
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path,paint);
}
public void setColor(Drawable color) {
if (color instanceof ColorDrawable) {
ColorDrawable colorDrawable= (ColorDrawable) color;
paint.setColor(colorDrawable.getColor());
} else if (color instanceof BitmapDrawable) {
this.drawable= (BitmapDrawable) color;
}
}
}
4 Demo
二 设置响应触摸区域
1 效果图
## 2 需求
当使用DrawerLayout实现侧拉栏效果时,经常发现手势的识别如左滑,响应效果不理想,特别是华为手机系统带左滑退出当前页面时;需要扩大滑动的识别区域
3 实现
public static void setDrawerLeftEdgeSize(Activity activity, DrawerLayout drawerLayout, float displayWidthPercentage) {
if (activity == null || drawerLayout == null) return;
try {
Field leftDraggerField = drawerLayout.getClass().getDeclaredField("mLeftDragger");
leftDraggerField.setAccessible(true);
ViewDragHelper leftDragger = (ViewDragHelper) leftDraggerField.get(drawerLayout);
Field edgeSizeField = leftDragger.getClass().getDeclaredField("mEdgeSize");
edgeSizeField.setAccessible(true);
int edgeSize = edgeSizeField.getInt(leftDragger);
DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
edgeSizeField.setInt(leftDragger, Math.max(edgeSize, (int) (dm.widthPixels * displayWidthPercentage)));
} catch (Exception e) {
}
}