自定义View ----QQ5.0左边侧滑 + 动画
16lz
2021-01-23
- xml
activity_main.xml
<?xml version="1.0" encoding="utf-8"?><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.guyulei.myqq50.DragLayout android:background="@mipmap/bk" android:id="@+id/dl_dragLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="vertical" android:background="#f00" android:layout_width="200dp" android:layout_height="match_parent"> <RelativeLayout android:background="#0ff" android:layout_width="match_parent" android:layout_height="150dp"> <ImageView android:layout_marginLeft="15dp" android:layout_centerVertical="true" android:src="@mipmap/qq4" android:layout_width="135dp" android:layout_height="135dp"/> RelativeLayout> <ListView android:id="@+id/left_listView" android:layout_width="match_parent" android:layout_height="match_parent"> ListView> LinearLayout> <LinearLayout android:orientation="vertical" android:background="#0f0" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:background="#f0f" android:layout_width="match_parent" android:layout_height="88dp"> <ImageView android:id="@+id/iv_head" android:layout_marginLeft="15dp" android:layout_centerVertical="true" android:src="@mipmap/qq4" android:layout_width="77dp" android:layout_height="77dp"/> RelativeLayout> <ListView android:id="@+id/main_listView" android:layout_width="match_parent" android:layout_height="match_parent"> ListView> LinearLayout> com.guyulei.myqq50.DragLayout>LinearLayout>
2.自定义view
public class DragLayout extends FrameLayout
package com.guyulei.myqq50;import android.content.Context;import android.graphics.Color;import android.graphics.PorterDuff;import android.support.v4.view.ViewCompat;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.FrameLayout;import android.widget.LinearLayout;/** * Created by Administrator on 2016/6/30 0030. * 1、为什么不继承 ViewGroup,因为继承 ViewGroup 需要重写 onMeasure()和实现 onLayout()方法,自己 * 实现子 view 的测量和摆放,在这里我们不需要自己去做测量和摆放,而 FrameLayout 已经对这两个方法进 * 行了具体实现,所以继承 FrameLayout 更加简单省事 * 2、为什么不继承 RelativeLayout,因为这里我们只需要层级关系,不需要相对关系,继承 RelativeLayout * 界面效果是一样的,但 RelativeLayout 对 FrameLayout 多了相对关系的计算,效率会低一些,所以选择继 * 承 FrameLayout */public class DragLayout extends FrameLayout { private ViewDragHelper mViewDragHelper; private LinearLayout mLeftContent; private LinearLayout mMainContent; private int mWidth; private int mHeight; private int mRange; private int mLeftWidth; //状态值 public enum Status { Open, Close, Draging; } //默认状态值 private Status status = Status.Close; //监听对象声明 private OnUpdataDragStateListener mOnUpdataDragStateListener; //对外接口 public interface OnUpdataDragStateListener { void onOpen(); void onClose(); void onDragging(float percent); } //对外接口回调方法 public void setOnUpdataDragStateListener(OnUpdataDragStateListener onUpdataDragStateListener) { this.mOnUpdataDragStateListener = onUpdataDragStateListener; } //串联构造方法 /** * 我们可以通过串连三个构造方法的方式实现只调用一次 init()方法 * 这样无论是代码创建还是布局在 xml 中都能调用到我们的初始化代码 * * @param context */ //代码创建时调用 public DragLayout(Context context) { this(context, null); } //布局在 xml 中,实例化时调用 public DragLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //初始化 //1.辅助类ViewDragHelper forparent 2个拖拽控件的父控件 ,sensitivity子控件拖拽的敏感度 //callback:事件回调 mViewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() { @Override // tryCaptureView俘获; 夺取; 夺得(尝试夺取子控件) //返回值代表 子控件 是否可以被夺取 public boolean tryCaptureView(View child, int pointerId) { return true; } //可通过计算测量水平或者垂直方向拖拽的范围 返回>0即可 @Override public int getViewHorizontalDragRange(View child) { return mRange; } @Override //clamp紧紧抓住; 紧夹住(紧抓着俘获的view(child)水平或者垂直移动位置) //dx 变化量(移动的差值 newleft-oldleft) public int clampViewPositionHorizontal(View child, int left, int dx) { //dx累加 是 left if (child == mMainContent) { //拖拽为主面板时 left = fixleft(left); } return left; } @Override //松手时 回调(Released释放) public void onViewReleased(View releasedChild, float xvel, float yvel) { // xvel水平方向上的速度 左为- 右为+ if (xvel == 0 && mMainContent.getLeft() > mRange / 2) { open(); } else if (xvel > 0) { //有向右的速度 open(); } else { close(); } } //位置发生移动 调用 @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { if (changedView == mLeftContent) { //控制底下的子控件不能移动(左面板) mLeftWidth = mLeftContent.getMeasuredWidth(); mLeftContent.layout(0, 0, mLeftWidth, mHeight); //左面板移动的距离 累加给主面板(移动左面板) int oldLeft = mMainContent.getLeft(); int newLeft = oldLeft + dx; //修正左边的位置 newLeft = fixleft(newLeft); mMainContent.layout(newLeft, 0, newLeft + mWidth, mHeight); } // dispatch派遣,调度; (迅速地)发出; 迅速处理 dispatchEvent(); invalidate(); } }); } //2 mViewDragHelper抢过触摸事件自己决定应该怎么处理 @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mViewDragHelper.shouldInterceptTouchEvent(ev); } //3.mViewDragHelper抢过触摸事件后,进行处理,返回值true @Override public boolean onTouchEvent(MotionEvent event) { mViewDragHelper.processTouchEvent(event); return true; } //4.onFinishInflate()在控件 inflate 完成时会被调用查找子控件 //可以通过 findViewById()的方式查找子控件 getChildAt(0) @Override protected void onFinishInflate() { super.onFinishInflate(); mLeftContent = (LinearLayout) getChildAt(0); mMainContent = (LinearLayout) getChildAt(1); } // 5.onSizeChanged()调用的次数比 onMeasure()少,在这里我们在 onSizeChanged()方法中去获取宽高 @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //获取整个控件的宽度和高度 mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); //主界面拖拽的范围(自定义)(0-mRange)(0 < left mRange = (int) (mWidth * 0.6f); } //6.修正左边的距离 private int fixleft(int left) { if (left < 0) { left = 0; } else if (left > mRange) { left = mRange; } return left; } //7.打开 smooth变平和,变缓和;Slide Mountain 斯来得山(凯次克来最高峰) //View child, int finalLeft, int finalTop private void open() { open(true); } private void open(boolean isSmooth) { int finalLeft = mRange; if (isSmooth) { //开启平滑 if (mViewDragHelper.smoothSlideViewTo(mMainContent, finalLeft, 0)) { //重绘界面 Compat兼容性; postInvalidateOnAnimation 动画结束之后再重绘 防止丢帧 ViewCompat.postInvalidateOnAnimation(this); } else { mMainContent.layout(finalLeft, 0, finalLeft + mWidth, mHeight); } } } //8. 关闭 private void close() { close(true); } private void close(boolean isSmooth) { int finalLeft = 0; if (isSmooth) { //开启平滑 if (mViewDragHelper.smoothSlideViewTo(mMainContent, finalLeft, 0)) { //重绘界面 //invalidate(); ViewCompat.postInvalidateOnAnimation(this); } else { mMainContent.layout(finalLeft, 0, finalLeft + mWidth, mHeight); } } } @Override public void computeScroll() { super.computeScroll(); //维持动画 if (mViewDragHelper.continueSettling(true)) { //重绘 ViewCompat.postInvalidateOnAnimation(this); } } //9.加动画 回调 private void dispatchEvent() { //获取 百分百 0.0f - 1.0f float percent = mMainContent.getLeft() * 1.0f / mRange; Status lastStatus = status; //状态更新 if (percent == 0) { status = Status.Close; } else if (percent == 1) { status = Status.Open; } else { status = Status.Draging; } //接口回调 if (mOnUpdataDragStateListener != null) { mOnUpdataDragStateListener.onDragging(percent); } // if (lastStatus != status && mOnUpdataDragStateListener != null) { if (status == Status.Open) { mOnUpdataDragStateListener.onOpen(); } else if (status == Status.Close) { mOnUpdataDragStateListener.onClose(); } } //左面板 缩放 位移 透明的 //0.0f-1.0f ---0.5f-1.0f //0.5f + percent * (0.5f); mLeftContent.setScaleX(0.5f + percent * (0.5f)); mLeftContent.setScaleY(0.5f + percent * (0.5f)); //位移 evaluate(percent,-mw,0) mLeftContent.setTranslationX(evaluate(percent, -mWidth * 0.5f, 0f)); //透明的evaluate(percent,0.2f,1.0f) mLeftContent.setAlpha(evaluate(percent, 0.2f, 1.0f)); //主面板 缩放evaluate(percent,0.2f,1.0f) mMainContent.setScaleY(evaluate(percent, 1.0f, 0.8f)); //背景亮度 滤波器Filter 估价,估值evaluate 门童; 搬运工人Porter欺骗; 把…改头换面;Duff getBackground().setColorFilter((Integer) evaluateColor(percent, Color.BLACK, Color.TRANSPARENT), PorterDuff.Mode.SRC_OVER); } public Object evaluateColor(float fraction, Object startValue, Object endValue) { int startInt = (Integer) startValue; int startA = (startInt >> 24) & 0xff; int startR = (startInt >> 16) & 0xff; int startG = (startInt >> 8) & 0xff; int startB = startInt & 0xff; int endInt = (Integer) endValue; int endA = (endInt >> 24) & 0xff; int endR = (endInt >> 16) & 0xff; int endG = (endInt >> 8) & 0xff; int endB = endInt & 0xff; return (int) ((startA + (int) (fraction * (endA - startA))) << 24) | (int) ((startR + (int) (fraction * (endR - startR))) << 16) | (int) ((startG + (int) (fraction * (endG - startG))) << 8) | (int) ((startB + (int) (fraction * (endB - startB)))); } public Float evaluate(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); }}
3.MainActivity
public class MainActivity extends Activity
package com.guyulei.myqq50;import android.animation.ValueAnimator;import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.view.animation.CycleInterpolator;import android.widget.ArrayAdapter;import android.widget.ImageView;import android.widget.ListView;import android.widget.TextView;import java.util.Random;import utils.MyToast;public class MainActivity extends Activity { private DragLayout mDragLayout; private ListView mMainlistView; private ListView mLeftlistView; private ImageView mIvhead; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //主页面imag对象 mIvhead = (ImageView) findViewById(R.id.iv_head); mDragLayout = (DragLayout) findViewById(R.id.dl_dragLayout); mDragLayout.setOnUpdataDragStateListener(new DragLayout.OnUpdataDragStateListener() { @Override public void onOpen() { MyToast.showToast(getApplicationContext(), "onOpen"); ////面板打开时,左面板上的 listview 随机滑动到 0 到 50 间的某个位置 mLeftlistView.smoothScrollToPosition(new Random().nextInt(20)); } @Override public void onClose() { MyToast.showToast(getApplicationContext(), "onClose"); ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 10f); valueAnimator.setDuration(1000); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); mIvhead.setTranslationX(value); } }); //动画插值器 valueAnimator.setInterpolator(new CycleInterpolator(3)); valueAnimator.start(); } @Override public void onDragging(float percent) { MyToast.showToast(getApplicationContext(), "onDragging" + percent); //percent 0.0f -> 1.0f => 1.0f -> 0.0f ==> 1-percent mIvhead.setAlpha(1-percent); } }); // mMainlistView = (ListView) findViewById(R.id.main_listView); //main数据 String[] str_main = new String[]{"guyulei", "guyulei1", "guyulei2", "guyulei3", "guyulei4" , "guyulei5", "guyulei6", "guyulei7", "guyulei8", "guyulei9", "guyulei10", "guyulei", "guyulei1", "guyulei2", "guyulei3", "guyulei4" , "guyulei5", "guyulei6", "guyulei7", "guyulei8", "guyulei9", "guyulei10", "guyulei", "guyulei1", "guyulei2", "guyulei3", "guyulei4" , "guyulei5", "guyulei6", "guyulei7", "guyulei8", "guyulei9", "guyulei10"}; //设置适配器:ArrayAdapter mMainlistView.setAdapter(new ArrayAdapter(getApplicationContext(), android.R.layout.simple_list_item_1, str_main) { @Override //重新getView 改变字体颜色 public View getView(int position, View convertView, ViewGroup parent) { TextView view = (TextView) super.getView(position, convertView, parent); view.setTextColor(Color.BLUE); return view; } }); // mLeftlistView = (ListView) findViewById(R.id.left_listView); String[] str_left = new String[]{"顾雨磊", "顾雨磊1", "顾雨磊2", "顾雨磊3", "顾雨磊4" , "顾雨磊5", "顾雨磊6", "顾雨磊7", "顾雨磊8", "顾雨磊9", "顾雨磊10", "顾雨磊11" , "顾雨磊12", "顾雨磊13", "顾雨磊14", "顾雨磊15", "顾雨磊16", "顾雨磊17", "顾雨磊18" , "顾雨磊19"}; mLeftlistView.setAdapter(new ArrayAdapter(getApplicationContext(), android.R.layout.simple_list_item_1, str_left) { @Override public View getView(int position, View convertView, ViewGroup parent) { TextView view = (TextView) super.getView(position, convertView, parent); view.setTextColor(Color.BLACK); return view; } }); }}
更多相关文章
- Android保持背光常亮的设置方法
- android EditText控件设置只读
- Android中定时器的3种实现方法
- Android与服务器通信的方法之一-->TCP
- Android ListView 控件学习
- ScrollView里面放入多个子控件
- android RadioButton文字居中的方法
- 编译NotificationManagerService.java文件的方法