Android自定義SwipeLayout仿QQ側(cè)滑條目
Android自定義SwipeLayout仿QQ側(cè)滑條目,供大家參考,具體內(nèi)容如下
先看動(dòng)圖
看布局文件
activity_main.xml
<RelativeLayout 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" tools:context="www.weshared.qqcehua.MainActivity"> <include layout="@layout/swipelayout" /> </RelativeLayout>
swipelayout.xml
<?xml version="1.0" encoding="utf-8"?> <www.weshared.qqcehua.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/swipelayout" android:layout_width="match_parent" android:layout_height="72dp"> <!--0 左邊后布局--> <TextView android:id="@+id/back_left_tv_mark" android:layout_width="84dp" android:layout_height="match_parent" android:background="@android:color/holo_blue_dark" android:gravity="center" android:text="Mark" android:textColor="@android:color/white" android:textSize="20sp" /> <!--1 右邊后布局--> <LinearLayout android:id="@+id/back_right_ll" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="right" android:orientation="horizontal"> <TextView android:id="@+id/back_right_tv_call" android:layout_width="84dp" android:layout_height="match_parent" android:background="@android:color/holo_orange_dark" android:gravity="center" android:text="Call" android:textColor="@android:color/white" android:textSize="20sp" /> <TextView android:id="@+id/back_right_tv_delete" android:layout_width="84dp" android:layout_height="match_parent" android:background="@android:color/holo_red_dark" android:gravity="center" android:text="Delete" android:textColor="@android:color/white" android:textSize="20sp" /> </LinearLayout> <!--2 前布局 content--> <TextView android:id="@+id/front_tv_content" android:layout_width="match_parent" android:layout_gravity="center" android:gravity="center" android:layout_height="match_parent" android:background="#666666" /> </www.weshared.qqcehua.SwipeLayout>
在MainActivity中
public class MainActivity extends AppCompatActivity { private SwipeLayout mSwipeLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { mSwipeLayout = (SwipeLayout) findViewById(R.id.swipelayout); mSwipeLayout.setOnClickListener(new SwipeLayout.OnClickListener() { @Override public void onClick(View view) { switch (view.getId()) { case R.id.back_left_tv_mark: toast("mark"); break; case R.id.front_tv_content: toast("content"); break; case R.id.back_right_tv_call: toast("call"); break; case R.id.back_right_tv_delete: toast("delete"); break; } } }); } public void toast(String message) { Toast toast = Toast.makeText(this, "", Toast.LENGTH_SHORT); if (!TextUtils.isEmpty(message) && toast != null) { toast.setText(message); toast.show(); } } }
自定義SwipeLayout控件
public class SwipeLayout extends FrameLayout { private View mBackLeftView; private ViewGroup mBackRightView; private View mFrontView; private int mWidth; private int mHeight; private int mLeftRange; private int mRightRange; private int status; public final int NORMAL = 0;//關(guān)閉狀態(tài) public final int LEFT_OPEN = 1;//左邊打開狀態(tài) public final int RIGHT_OPEN = 2;//右邊打開狀態(tài) public final int LEFT_OPENING = 3;//左邊正打開狀態(tài) public final int LEFT_CLOSING = 4;//左邊正關(guān)閉狀態(tài) public final int RIGHT_OPENING = 5;//右邊正打開狀態(tài) public final int RIGHT_CLOSING = 6;//右邊正關(guān)閉狀態(tài) private ViewDragHelper mViewDrawHelper; private final int V = 300;//限制速度 private OnSwipeListener mOnSwipeListener; private OnClickListener mOnClickListener; private View mBackRightCall; private View mBackRightDelete; private int x; private boolean isClick; private final int DX = 10; public interface OnSwipeListener { void onLeftOpen(SwipeLayout swipeLayout); void onLeftClose(SwipeLayout swipeLayout); void onRightOpen(SwipeLayout swipeLayout); void onRightClose(SwipeLayout swipeLayout); } public interface OnClickListener { void onClick(View view); } public SwipeLayout(Context context) { super(context); init(); } public SwipeLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init() { status = NORMAL;//默認(rèn)是NORMAL mViewDrawHelper = ViewDragHelper.create(this, callback); } public void setOnSwipeListener(OnSwipeListener mOnSwipeListener) { this.mOnSwipeListener = mOnSwipeListener; } public void setOnClickListener(OnClickListener mOnClickListener) { this.mOnClickListener = mOnClickListener; } private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { /**是否試圖拖拽子view*/ @Override public boolean tryCaptureView(View child, int pointerId) { if (child == mBackLeftView) { return false; } return true; } /** 水平方向上的限制*/ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (child == mFrontView) { if (left < -mRightRange) { left = -mRightRange; } else if (left > mLeftRange) { left = mLeftRange; } } else if (child == mBackRightView) { if (left < mWidth - mRightRange) { left = mWidth - mRightRange; } else if (left > mWidth) { left = mWidth; } } return left; } /**這是系統(tǒng)定義的狀態(tài)*/ @Override public void onViewDragStateChanged(int state) { super.onViewDragStateChanged(state); if (state == ViewDragHelper.STATE_IDLE) {//ViewDrawHelper處于空閑狀態(tài) } else if (state == ViewDragHelper.STATE_DRAGGING) {//ViewDrawHelper處于正在拖拽狀態(tài) //拖拽狀態(tài),可設(shè)置滑動(dòng)事件 } else if (state == ViewDragHelper.STATE_SETTLING) {//ViewDrawHelper處于飛翔狀態(tài) //飛翔狀態(tài)設(shè)置,可設(shè)置滾動(dòng)事件 } } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); if (mFrontView == changedView) { mBackRightView.offsetLeftAndRight(dx); } else if (mBackRightView == changedView) { mFrontView.offsetLeftAndRight(dx); } status = updateStatus();//更新控件的狀態(tài) invalidate();//重繪界面 } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); int left = mFrontView.getLeft(); if (left < -mRightRange * 0.5f) { if (xvel > V) { normalClose(); } else { rightOpen(); } } else if (left >= -mRightRange * 0.5f && left <= 0) { if (xvel < -V) {//向左滑動(dòng) rightOpen();//打開右邊前布局 } else { normalClose(); } } else if (left > 0 && left <= mLeftRange * 0.5f) { if (xvel > V) { leftOpen(); } else { normalClose(); } } else if (left > mLeftRange * 0.5f && left <= mLeftRange) { if (xvel < -V) {//向左滑動(dòng) normalClose(); } else { leftOpen(); } } } }; public void dispatchClickListener() { //設(shè)置點(diǎn)擊事件 if (status == LEFT_OPEN) { //mark的點(diǎn)擊事件和Content點(diǎn)擊事件 if (mOnClickListener != null) { if (x > 0 && x < mLeftRange) { mOnClickListener.onClick(mBackLeftView); } } } else if (status == RIGHT_OPEN) { //call 和 Delete的點(diǎn)擊事件 和Content點(diǎn)擊事件 if (mOnClickListener != null) { if (x > mWidth - mRightRange && x < mWidth - mRightRange * 0.5f) { mOnClickListener.onClick(mBackRightCall); } else if (x >= mWidth - mRightRange * 0.5f && x <= mWidth) { mOnClickListener.onClick(mBackRightDelete); } } } else if (status == NORMAL) { //content的點(diǎn)擊事件 if (mOnClickListener != null) { mOnClickListener.onClick(mFrontView); } } } private int updateStatus() { int left = mFrontView.getLeft(); if (left == -mRightRange) { status = RIGHT_OPEN; } else if (left == 0) { status = NORMAL; } else if (left == mLeftRange) { status = LEFT_OPEN; } return status; } public void leftOpen() { leftOpen(true); } public void leftOpen(boolean isSmooth) { int finalLeft = mLeftRange; int finalTop = 0; if (isSmooth) { if (mViewDrawHelper.smoothSlideViewTo(mFrontView, finalLeft, finalTop)) { ViewCompat.postInvalidateOnAnimation(this); } } else { layoutContent(LEFT_OPEN); } } public void normalClose() { normalClose(true); } public void normalClose(boolean isSmooth) { int finalLeft = 0; int finalTop = 0; if (isSmooth) { if (mViewDrawHelper.smoothSlideViewTo(mFrontView, finalLeft, finalTop)) { ViewCompat.postInvalidateOnAnimation(this); } } else { layoutContent(NORMAL); } } public void rightOpen() { rightOpen(true); } public void rightOpen(boolean isSmooth) { int finalLeft = -mRightRange; int finalTop = 0; if (isSmooth) { if (mViewDrawHelper.smoothSlideViewTo(mFrontView, finalLeft, finalTop)) { ViewCompat.postInvalidateOnAnimation(this); } } else { layoutContent(RIGHT_OPEN); } } @Override public void computeScroll() { super.computeScroll(); if (mViewDrawHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mViewDrawHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { dispatchOnTouchEvent(event);//分發(fā)觸摸的事件 try { mViewDrawHelper.processTouchEvent(event);//將觸摸事件傳遞給ViewDrawHelper } catch (Exception e) { } return true; } public void dispatchOnTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { x = (int) event.getX(); isClick = true; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { int movex = (int) event.getX(); if (Math.abs(movex - x) > DX) {//防止點(diǎn)擊事件,會(huì)稍微手指抖動(dòng) isClick = false; } } else if (event.getAction() == MotionEvent.ACTION_UP) { if (isClick) { dispatchClickListener(); } } } @Override protected void onFinishInflate() { super.onFinishInflate(); //獲取控件中的子控件 mBackLeftView = getChildAt(0); mBackRightView = (ViewGroup) getChildAt(1); mFrontView = getChildAt(2); mBackRightCall = mBackRightView.getChildAt(0); mBackRightDelete = mBackRightView.getChildAt(1); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); mLeftRange = mBackLeftView.getMeasuredWidth(); mRightRange = mBackRightView.getMeasuredWidth(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); //擺放布局 layoutContent(NORMAL); } public void layoutContent(int status) { Rect frontRect = computeFrontRect(status);//根據(jù)狀態(tài),擺放前布局 mFrontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom); Rect rightBackRect = computeRightBackRect(frontRect);//根據(jù)前布局,擺放右邊后布局 mBackRightView.layout(rightBackRect.left, rightBackRect.top, rightBackRect.right, rightBackRect.bottom); } public Rect computeFrontRect(int status) { int left = 0; int top = 0; if (status == LEFT_OPEN) { left = mLeftRange; } else if (status == RIGHT_OPEN) { left = -mRightRange; } return new Rect(left, top, left + mWidth, top + mHeight); } public Rect computeRightBackRect(Rect frontRect) { int left = 0; int top = 0; if (frontRect != null) { left = frontRect.right; } return new Rect(left, top, left + mRightRange, top + mHeight); } }
現(xiàn)在控件耦合程度太高,以后慢慢優(yōu)化,寫成一個(gè)庫。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android RecyclerView實(shí)現(xiàn)點(diǎn)擊條目刪除
- Android仿京東分類模塊左側(cè)分類條目效果
- Android更多條目收縮展開控件ExpandView的示例代碼
- Android ListView自動(dòng)生成列表?xiàng)l目的實(shí)例
- Android XRecyclerView實(shí)現(xiàn)多條目加載
- Android條目拖拽刪除功能實(shí)例代碼
- Android ListView 條目多樣式展示實(shí)例詳解
- android RecyclerView實(shí)現(xiàn)條目Item拖拽排序與滑動(dòng)刪除
- Android中l(wèi)istview和imageview實(shí)現(xiàn)條目單選效果
- Android編程實(shí)現(xiàn)canvas繪制餅狀統(tǒng)計(jì)圖功能示例【自動(dòng)適應(yīng)條目數(shù)量與大小】
- Android中RecyclerView上拉下拉,分割線,多條目的實(shí)例代碼
- Android 中 SwipeLayout一個(gè)展示條目底層菜單的側(cè)滑控件源碼解析
- 詳解Android中實(shí)現(xiàn)ListView左右滑動(dòng)刪除條目的方法
- Android實(shí)現(xiàn)下拉展示條目效果
相關(guān)文章
Android UI設(shè)計(jì)之AlertDialog彈窗控件
這篇文章主要為大家詳細(xì)介紹了Android UI設(shè)計(jì)之AlertDialog彈窗控件的使用方法,感興趣的小伙伴們可以參考一下2016-08-08Android實(shí)現(xiàn)隱藏狀態(tài)欄和標(biāo)題欄
這篇文章主要介紹了Android實(shí)現(xiàn)隱藏狀態(tài)欄和標(biāo)題欄的相關(guān)資料,需要的朋友可以參考下2015-06-06Android編程實(shí)現(xiàn)添加低電流提醒功能的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)添加低電流提醒功能的方法,涉及Android廣播監(jiān)聽及電源監(jiān)控等相關(guān)操作技巧,需要的朋友可以參考下2017-09-09Android 實(shí)現(xiàn)九宮格抽獎(jiǎng)功能
這篇文章主要介紹了Android 實(shí)現(xiàn)九宮格抽獎(jiǎng)功能,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-03-03Android中傳遞對象的三種方法的實(shí)現(xiàn)
本篇文章主要介紹了Android中傳遞對象的三種方法的實(shí)現(xiàn),可以通過Bundle、Intent或者JSON字符串,有興趣的可以了解一下。2017-02-02Android編程使用pull方式解析xml格式文件的方法詳解
這篇文章主要介紹了Android編程使用pull方式解析xml格式文件的方法,結(jié)合實(shí)例形式分析了Android調(diào)用pull解析器操作xml格式文件的步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-07-07Android轉(zhuǎn)場效果實(shí)現(xiàn)示例淺析
這篇文章主要為大家介紹了Android轉(zhuǎn)場效果實(shí)現(xiàn)示例淺析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02深入理解Android熱修復(fù)技術(shù)原理之資源熱修復(fù)技術(shù)
Android資源的熱修復(fù),就是在app不重新安裝的情況下,利用下發(fā)的補(bǔ)丁包 直接更新本app中的資源2021-06-06