国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

ViewDragHelper實現QQ側滑效果

2019-10-22 18:29:04
字體:
來源:轉載
供稿:網友

前言

       側滑的實現方式有很多方式來實現,這次總結的ViewDragHelper就是其中一種方式,ViewDragHelper是2013年谷歌I/O大會發布的新的控件,為了解決界面控件拖拽問題。下面就是自己學習寫的一個實現類似于QQ側滑效果的實現。
activity_main.xml:

<com.yctc.drag.DragLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/dl" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bg" tools:context=".MainActivity" > <LinearLayout  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical"  android:paddingBottom="50dp"  android:paddingLeft="10dp"  android:paddingRight="50dp"  android:paddingTop="50dp" >  <ImageView   android:layout_width="50dp"   android:layout_height="50dp"   android:src="@drawable/head" />  <ListView   android:id="@+id/lv_left"   android:layout_width="match_parent"   android:layout_height="match_parent" >  </ListView> </LinearLayout> <com.yctc.drag.MyLinearLayout  android:id="@+id/mll"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:background="#ffffff"  android:orientation="vertical" >  <RelativeLayout   android:layout_width="match_parent"   android:layout_height="50dp"   android:background="#18B6EF"   android:gravity="center_vertical" >   <ImageView    android:id="@+id/iv_header"    android:layout_width="30dp"    android:layout_height="30dp"    android:layout_marginLeft="15dp"    android:src="@drawable/head" />   <TextView    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_centerHorizontal="true"    android:text="Header" />  </RelativeLayout>  <ListView   android:id="@+id/lv_main"   android:layout_width="match_parent"   android:layout_height="match_parent" >  </ListView> </com.yctc.drag.MyLinearLayout></com.yctc.drag.DragLayout>

 

DragLayout.Java:

public class DragLayout extends FrameLayout { private static final String TAG = "TAG"; private ViewDragHelper mDragHelper; private ViewGroup mLeftContent; private ViewGroup mMainContent; private OnDragStatusChangeListener mListener; private Status mStatus = Status.Close; /**  * 狀態枚舉  */ public static enum Status {  Close, Open, Draging; } public interface OnDragStatusChangeListener{  void onClose();  void onOpen();  void onDraging(float percent); } public Status getStatus() {  return mStatus; } public void setStatus(Status mStatus) {  this.mStatus = mStatus; } public void setDragStatusListener(OnDragStatusChangeListener mListener){  this.mListener = mListener; } public DragLayout(Context context) {  this(context, null); } public DragLayout(Context context, AttributeSet attrs) {  this(context, attrs, 0); } public DragLayout(Context context, AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle);  // a.初始化 (通過靜態方法)   mDragHelper = ViewDragHelper.create(this , mCallback); } ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {  // c. 重寫事件  // 1. 根據返回結果決定當前child是否可以拖拽  // child 當前被拖拽的View  // pointerId 區分多點觸摸的id  @Override  public boolean tryCaptureView(View child, int pointerId) {   Log.d(TAG, "tryCaptureView: " + child);   return true;  };  @Override  public void onViewCaptured(View capturedChild, int activePointerId) {   Log.d(TAG, "onViewCaptured: " + capturedChild);   // 當capturedChild被捕獲時,調用.   super.onViewCaptured(capturedChild, activePointerId);  }  @Override  public int getViewHorizontalDragRange(View child) {   // 返回拖拽的范圍, 不對拖拽進行真正的限制. 僅僅決定了動畫執行速度   return mRange;  }  // 2. 根據建議值 修正將要移動到的(橫向)位置 (重要)  // 此時沒有發生真正的移動  public int clampViewPositionHorizontal(View child, int left, int dx) {   // child: 當前拖拽的View   // left 新的位置的建議值, dx 位置變化量   // left = oldLeft + dx;   Log.d(TAG, "clampViewPositionHorizontal: "      + "oldLeft: " + child.getLeft() + " dx: " + dx + " left: " +left);   if(child == mMainContent){    left = fixLeft(left);   }   return left;  }  // 3. 當View位置改變的時候, 處理要做的事情 (更新狀態, 伴隨動畫, 重繪界面)  // 此時,View已經發生了位置的改變  @Override  public void onViewPositionChanged(View changedView, int left, int top,    int dx, int dy) {   // changedView 改變位置的View   // left 新的左邊值   // dx 水平方向變化量   super.onViewPositionChanged(changedView, left, top, dx, dy);   Log.d(TAG, "onViewPositionChanged: " + "left: " + left + " dx: " + dx);   int newLeft = left;   if(changedView == mLeftContent){    // 把當前變化量傳遞給mMainContent    newLeft = mMainContent.getLeft() + dx;   }   // 進行修正   newLeft = fixLeft(newLeft);   if(changedView == mLeftContent) {    // 當左面板移動之后, 再強制放回去.    mLeftContent.layout(0, 0, 0 + mWidth, 0 + mHeight);    mMainContent.layout(newLeft, 0, newLeft + mWidth, 0 + mHeight);   }   // 更新狀態,執行動畫   dispatchDragEvent(newLeft);   // 為了兼容低版本, 每次修改值之后, 進行重繪   invalidate();  }  // 4. 當View被釋放的時候, 處理的事情(執行動畫)  @Override  public void onViewReleased(View releasedChild, float xvel, float yvel) {   // View releasedChild 被釋放的子View    // float xvel 水平方向的速度, 向右為+   // float yvel 豎直方向的速度, 向下為+   Log.d(TAG, "onViewReleased: " + "xvel: " + xvel + " yvel: " + yvel);   super.onViewReleased(releasedChild, xvel, yvel);   // 判斷執行 關閉/開啟   // 先考慮所有開啟的情況,剩下的就都是關閉的情況   if(xvel == 0 && mMainContent.getLeft() > mRange / 2.0f){    open();   }else if (xvel > 0) {    open();   }else {    close();   }  }  @Override  public void onViewDragStateChanged(int state) {   // TODO Auto-generated method stub   super.onViewDragStateChanged(state);  } }; /**  * 根據范圍修正左邊值  * @param left  * @return  */ private int fixLeft(int left) {  if(left < 0){   return 0;  }else if (left > mRange) {   return mRange;  }  return left; } protected void dispatchDragEvent(int newLeft) {  float percent = newLeft * 1.0f/ mRange;  //0.0f -> 1.0f  Log.d(TAG, "percent: " + percent);  if(mListener != null){   mListener.onDraging(percent);  }  // 更新狀態, 執行回調  Status preStatus = mStatus;  mStatus = updateStatus(percent);  if(mStatus != preStatus){   // 狀態發生變化   if(mStatus == Status.Close){    // 當前變為關閉狀態    if(mListener != null){     mListener.onClose();    }   }else if (mStatus == Status.Open) {    if(mListener != null){     mListener.onOpen();    }   }  }//  * 伴隨動畫:  animViews(percent); } private Status updateStatus(float percent) {  if(percent == 0f){   return Status.Close;  }else if (percent == 1.0f) {   return Status.Open;  }  return Status.Draging; } private void animViews(float percent) {  //  > 1. 左面板: 縮放動畫, 平移動畫, 透明度動畫     // 縮放動畫 0.0 -> 1.0 >>> 0.5f -> 1.0f >>> 0.5f * percent + 0.5f   //  mLeftContent.setScaleX(0.5f + 0.5f * percent);   //  mLeftContent.setScaleY(0.5f + 0.5f * percent);     ViewHelper.setScaleX(mLeftContent, evaluate(percent, 0.5f, 1.0f));     ViewHelper.setScaleY(mLeftContent, 0.5f + 0.5f * percent);     // 平移動畫: -mWidth / 2.0f -> 0.0f     ViewHelper.setTranslationX(mLeftContent, evaluate(percent, -mWidth / 2.0f, 0));     // 透明度: 0.5 -> 1.0f     ViewHelper.setAlpha(mLeftContent, evaluate(percent, 0.5f, 1.0f));  //  > 2. 主面板: 縮放動畫     // 1.0f -> 0.8f     ViewHelper.setScaleX(mMainContent, evaluate(percent, 1.0f, 0.8f));     ViewHelper.setScaleY(mMainContent, evaluate(percent, 1.0f, 0.8f));  //  > 3. 背景動畫: 亮度變化 (顏色變化)     getBackground().setColorFilter((Integer)evaluateColor(percent, Color.BLACK, Color.TRANSPARENT), Mode.SRC_OVER); } /**  * 估值器  * @param fraction  * @param startValue  * @param endValue  * @return  */ public Float evaluate(float fraction, Number startValue, Number endValue) {  float startFloat = startValue.floatValue();  return startFloat + fraction * (endValue.floatValue() - startFloat); } /**  * 顏色變化過度  * @param fraction  * @param startValue  * @param endValue  * @return  */ 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)))); } @Override public void computeScroll() {  super.computeScroll();  // 2. 持續平滑動畫 (高頻率調用)  if(mDragHelper.continueSettling(true)){   // 如果返回true, 動畫還需要繼續執行   ViewCompat.postInvalidateOnAnimation(this);  } } public void close(){  close(true); } /**  * 關閉  */ public void close(boolean isSmooth) {  int finalLeft = 0;  if(isSmooth){   // 1. 觸發一個平滑動畫   if(mDragHelper.smoothSlideViewTo(mMainContent, finalLeft, 0)){    // 返回true代表還沒有移動到指定位置, 需要刷新界面.    // 參數傳this(child所在的ViewGroup)    ViewCompat.postInvalidateOnAnimation(this);   }  }else {   mMainContent.layout(finalLeft, 0, finalLeft + mWidth, 0 + mHeight);  } } public void open(){  open(true); } /**  * 開啟  */ public void open(boolean isSmooth) {  int finalLeft = mRange;  if(isSmooth){   // 1. 觸發一個平滑動畫   if(mDragHelper.smoothSlideViewTo(mMainContent, finalLeft, 0)){    // 返回true代表還沒有移動到指定位置, 需要刷新界面.    // 參數傳this(child所在的ViewGroup)    ViewCompat.postInvalidateOnAnimation(this);   }  }else {   mMainContent.layout(finalLeft, 0, finalLeft + mWidth, 0 + mHeight);  } } private int mHeight; private int mWidth; private int mRange; // b.傳遞觸摸事件 @Override public boolean onInterceptTouchEvent(MotionEvent ev) {  // 傳遞給mDragHelper  return mDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) {  try {   mDragHelper.processTouchEvent(event);  } catch (Exception e) {   e.printStackTrace();  }  // 返回true, 持續接受事件  return true; } @Override protected void onFinishInflate() {  super.onFinishInflate();  // Github  // 寫注釋  // 容錯性檢查 (至少有倆子View, 子View必須是ViewGroup的子類)  if(getChildCount() < 2){   throw new IllegalStateException("布局至少有倆孩子. Your ViewGroup must have 2 children at least.");  }  if(!(getChildAt(0) instanceof ViewGroup && getChildAt(1) instanceof ViewGroup)){   throw new IllegalArgumentException("子View必須是ViewGroup的子類. Your children must be an instance of ViewGroup");  }  mLeftContent = (ViewGroup) getChildAt(0);  mMainContent = (ViewGroup) getChildAt(1); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {  super.onSizeChanged(w, h, oldw, oldh);  // 當尺寸有變化的時候調用  mHeight = getMeasuredHeight();  mWidth = getMeasuredWidth();  // 移動的范圍  mRange = (int) (mWidth * 0.6f); }}

MyLineatLayout.java:

public class MyLinearLayout extends LinearLayout { private DragLayout mDragLayout; public MyLinearLayout(Context context) {  super(context); } public MyLinearLayout(Context context, AttributeSet attrs) {  super(context, attrs); } public void setDraglayout(DragLayout mDragLayout){  this.mDragLayout = mDragLayout; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) {  // 如果當前是關閉狀態, 按之前方法判斷  if(mDragLayout.getStatus() == Status.Close){   return super.onInterceptTouchEvent(ev);  }else {   return true;  } } @Override public boolean onTouchEvent(MotionEvent event) {  // 如果當前是關閉狀態, 按之前方法處理  if(mDragLayout.getStatus() == Status.Close){   return super.onTouchEvent(event);  }else {   // 手指抬起, 執行關閉操作   if(event.getAction() == MotionEvent.ACTION_UP){    mDragLayout.close();   }   return true;  } }}

MainActivity.java:

public class MainActivity extends Activity { private static final String TAG = "TAG"; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  requestWindowFeature(Window.FEATURE_NO_TITLE);  setContentView(R.layout.activity_main);  final ListView mLeftList = (ListView) findViewById(R.id.lv_left);  final ListView mMainList = (ListView) findViewById(R.id.lv_main);  final ImageView mHeaderImage = (ImageView) findViewById(R.id.iv_header);  MyLinearLayout mLinearLayout = (MyLinearLayout) findViewById(R.id.mll);  // 查找Draglayout, 設置監聽  DragLayout mDragLayout = (DragLayout) findViewById(R.id.dl);  // 設置引用  mLinearLayout.setDraglayout(mDragLayout);  mDragLayout.setDragStatusListener(new OnDragStatusChangeListener() {   @Override   public void onOpen() {    Utils.showToast(MainActivity.this, "onOpen");    // 左面板ListView隨機設置一個條目    Random random = new Random();    int nextInt = random.nextInt(50);    mLeftList.smoothScrollToPosition(nextInt);   }   @Override   public void onDraging(float percent) {    Log.d(TAG, "onDraging: " + percent);// 0 -> 1    // 更新圖標的透明度    // 1.0 -> 0.0    ViewHelper.setAlpha(mHeaderImage, 1 - percent);   }   @Override   public void onClose() {    Utils.showToast(MainActivity.this, "onClose");    // 讓圖標晃動//    mHeaderImage.setTranslationX(translationX)    ObjectAnimator mAnim = ObjectAnimator.ofFloat(mHeaderImage, "translationX", 15.0f);    mAnim.setInterpolator(new CycleInterpolator(4));    mAnim.setDuration(500);    mAnim.start();   }  });  mLeftList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Cheeses.sCheeseStrings){   @Override   public View getView(int position, View convertView, ViewGroup parent) {    View view = super.getView(position, convertView, parent);    TextView mText = ((TextView)view);    mText.setTextColor(Color.WHITE);    return view;   }  });  mMainList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Cheeses.NAMES))   }}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 嘉黎县| 滁州市| 泾源县| 德惠市| 松滋市| 沭阳县| 五指山市| 彭州市| 黄冈市| 鹿邑县| 思南县| 沙洋县| 乌拉特前旗| 久治县| 德安县| 城口县| 扶余县| 永福县| 元氏县| 石城县| 孟州市| 广宁县| 昭平县| 平武县| 理塘县| 邵阳县| 泗阳县| 石河子市| 鄂伦春自治旗| 乐安县| 萝北县| 灵石县| 新宾| 大荔县| 德兴市| 邛崃市| 阳朔县| 田东县| 闽侯县| 石狮市| 青田县|