版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】Android中如何通過ViewDragHelper實現(xiàn)ListView的Item的側(cè)拉劃出效果
/upload/information/20200623/125/126976.gif實現(xiàn)該自定義控件的大體步驟如下:/upload/information/20200623/125/126977.png/upload/information/20200623/125/126978.png以上2部分就是該自定義控件要包含的2個直接子View./**
*
Created
by
mChenys
on
2015/12/26.
*/
public
class
SwipeLayout
extends
FrameLayout
{
private
ViewDragHelper.Callback
mCallback;
private
ViewDragHelper
mDragHelper;
private
View
mBackView;
//item的側(cè)邊布局
private
View
mFrontView;//當前顯示的item布局
private
int
mWidth;
//屏幕的寬度,mFrontView的寬度
private
int
mHeight;
//mFrontView的高度
private
int
mRange;//mFrontView側(cè)拉時向左移動的最大距離,即mBackView的寬度
public
SwipeLayout(Context
context)
{
this(context,
null);
}
public
SwipeLayout(Context
context,
AttributeSet
attrs)
{
this(context,
attrs,
0);
}
public
SwipeLayout(Context
context,
AttributeSet
attrs,
int
defStyleAttr)
{
super(context,
attrs,
defStyleAttr);
init();
}
//1.初始ViewDragHelper
private
void
init()
{
mCallback
=
new
ViewDragHelper.Callback()
{
//3.在回調(diào)方法中處理觸摸事件
@Override
public
boolean
tryCaptureView(View
child,
int
pointerId)
{
return
true;
//允許所有子控件的滑動
}
//設(shè)定滑動的邊界值
@Override
public
int
clampViewPositionHorizontal(View
child,
int
left,
int
dx)
{
if
(child
==
mFrontView)
{
//前景View的滑動范圍是(0~
-mRange)
if
(left
>
0)
{
left
=
0;
}
else
if
(left
<
-mRange)
{
left
=
-mRange;
}
}
if
(child
==
mBackView)
{
//背景View的滑動范圍是(mWidth
-
mRange
~
mWidth)
if
(left
>
mWidth)
{
left
=
mWidth;
}
else
if
(left
<
(mWidth
-
mRange))
{
left
=
mWidth
-
mRange;
}
}
//返回修正過的建議值
return
left;
}
//監(jiān)聽View的滑動位置的改變,同步前景View和背景View的滑動事件
@Override
public
void
onViewPositionChanged(View
changedView,
int
left,
int
top,
int
dx,
int
dy)
{
if
(changedView
==
mFrontView)
{
//當滑動前景View時,也需要滑動背景View
mBackView.offsetLeftAndRight(dx);
}
else
if
(changedView
==
mBackView)
{
//當滑動背景View時,也需要滑動前景View
mFrontView.offsetLeftAndRight(dx);
}
//
兼容老版本
invalidate();
}
//處理釋放后的開啟和關(guān)閉動作
@Override
public
void
onViewReleased(View
releasedChild,
float
xvel,
float
yvel)
{
if
(xvel
<
0)
{
//有向左滑動的速度,則打開
open();
}
else
if
(xvel
==
0
&&
mFrontView.getLeft()
<
-mRange
/
2.0f)
{
//前景View向左滑動的left小于背景View寬度一半的負值時,打開
open();
}
else
{
//其他情況為關(guān)閉
close();
}
}
};
mDragHelper
=
ViewDragHelper.create(this,
mCallback);
}
//2.傳遞觸摸事件
@Override
public
boolean
onInterceptTouchEvent(MotionEvent
ev)
{
return
mDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public
boolean
onTouchEvent(MotionEvent
event)
{
try
{
mDragHcessTouchEvent(event);
}
catch
(Exception
e)
{
e.printStackTrace();
}
return
true;
}
//獲取子控件的引用
@Override
protected
void
onFinishInflate()
{
super.onFinishInflate();
mBackView
=
getChildAt(0);
//獲取背景View,即展示數(shù)據(jù)的Item的右邊隱藏的側(cè)滑布局
mFrontView
=
getChildAt(1);//獲取前景View,即展示數(shù)據(jù)的Item
}
//獲取子控件的相關(guān)寬高信息
@Override
protected
void
onSizeChanged(int
w,
int
h,
int
oldw,
int
oldh)
{
super.onSizeChanged(w,
h,
oldw,
oldh);
mWidth
=
mFrontView.getMeasuredWidth();
mHeight
=
mFrontView.getMeasuredHeight();
mRange
=
mBackView.getMeasuredWidth();
}
//確定子控件的初始位置
@Override
protected
void
onLayout(boolean
changed,
int
left,
int
top,
int
right,
int
bottom)
{
super.onLayout(changed,
left,
top,
right,
bottom);
layoutChildView(false);
}
/**
*
放置子控件的位置
*
*
@param
isOpen
是否是打開前景View,true打開,false關(guān)閉
*/
private
void
layoutChildView(boolean
isOpen)
{
//計算前景View的位置,將坐標信息封裝到矩形中
Rect
fontRect
=
computerFontViewRect(isOpen);
//擺放前景View
mFrontView.layout(fontRect.left,
fontRect.top,
fontRect.right,
fontRect.bottom);
//擺放背景View,left坐標是前景View的right坐標
int
left
=
fontRect.right;
mBackView.layout(left,
0,
left
+
mRange,
mHeight);
//由于上面是后擺放背景View,所以會覆蓋前景View,因此需要通過下面的方式將前景View顯示在前面
bringChildToFront(mFrontView);
}
/**
*
計算前景View的坐標
*
*
@param
isOpen
是否是打開前景View
*
@return
*/
private
Rect
computerFontViewRect(boolean
isOpen)
{
int
left
=
isOpen
?
-mRange
:
0;
return
new
Rect(left,
0,
left
+
mWidth,
mHeight);
}
/**
*
打開側(cè)邊欄mBackView,默認平滑打開
*/
public
void
open()
{
open(true);
}
/**
*
打開側(cè)邊欄mBackView
*
*
@param
isSmooth
是否平滑打開
*/
public
void
open(boolean
isSmooth)
{
if
(isSmooth)
{
if
(mDragHelper.smoothSlideViewTo(mFrontView,
-mRange,
0))
{
//動畫在繼續(xù)
ViewCompat.postInvalidateOnAnimation(this);
}
}
else
{
layoutChildView(true);
}
}
/**
*
關(guān)閉側(cè)邊欄mBackView,默認平滑關(guān)閉
*/
public
void
close()
{
close(true);
}
/**
*
關(guān)閉側(cè)邊欄mBackView
*
*
@param
isSmooth
是否平滑關(guān)閉
*/
public
void
close(boolean
isSmooth)
{
if
(isSmooth)
{
if
(mDragHelper.smoothSlideViewTo(mBackView,
mWidth,
0))
{
//動畫在繼續(xù)
ViewCompat.postInvalidateOnAnimation(this);
}
}
else
{
layoutChildView(false);
}
}
@Override
public
void
computeScroll()
{
puteScroll();
if
(mDragHelper.continueSettling(true))
{
//動畫還在繼續(xù)
ViewCompat.postInvalidateOnAnimation(this);
}
}
}<?xml
version="1.0"
encoding="utf-8"?>
<.csdn.blog.myswipelayout.view.SwipeLayout
xmlns:android="/apk/res/android"
android:id="@+id/sl"
android:layout_width="match_parent"
android:layout_height="60dp"
android:minHeight="60dp"
android:background="#44000000"
>
<!--后置布局-->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<TextView
android:id="@+id/tv_call"
android:layout_width="60dp"
android:layout_height="match_parent"
android:background="#666666"
android:gravity="center"
android:text="Edit"
android:textColor="#ffffff"
/>
<TextView
android:id="@+id/tv_del"
android:layout_width="60dp"
android:layout_height="match_parent"
android:background="#ff0000"
android:gravity="center"
android:text="Delete"
android:textColor="#ffffff"
/>
</LinearLayout>
<!--前景布局-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44ffffff"
android:gravity="center_vertical"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/iv_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="15dp"
android:src="@drawable/head_1"
/>
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="Name"
/>
</LinearLayout>
</.csdn.blog.myswipelayout.view.SwipeLayout>/upload/information/20200623/125/126979.gif需要考慮2點:/**
*
側(cè)拉SwipeLayout的監(jiān)聽
*
Created
by
mChenys
on
2015/12/26.
*/
public
interface
SwipeViewListener
{
//關(guān)閉
void
onClose(SwipeLayout
mSwipeLayout);
//打開
void
onOpen(SwipeLayout
mSwipeLayout);
//正在側(cè)拉
void
onDraging(SwipeLayout
mSwipeLayout);
//開始要去關(guān)閉
void
onStartClose(SwipeLayout
mSwipeLayout);
//開始要去開啟
void
onStartOpen(SwipeLayout
mSwipeLayout);
}//以下是定義SwipeLayout的打開,關(guān)閉,滑動的3種狀態(tài)
public
enum
Status
{
CLOSE,
OPEN,
DRAGING;
}
//默認關(guān)閉
private
Status
mStatus
=
Status.CLOSE;
//滑動的監(jiān)聽器
private
SwipeViewListener
mSwipeViewListener;
//設(shè)置監(jiān)聽器
public
void
setSwipeViewListener(SwipeViewListener
swipeViewListener)
{
mSwipeViewListener
=
swipeViewListener;
}/**
*
處理滑動,打開,關(guān)閉的3種情況
*
在onViewPositionChanged
調(diào)用
*/
private
void
dispatchSwipeEvent()
{
if
(mSwipeViewListener
!=
null)
{
mSwipeViewListener.onDraging(this);
}
//記錄上一次的狀態(tài)
Status
preStatus
=
mStatus;
//獲取當前的狀態(tài)
mStatus
=
getCurrStatus();
if
(preStatus
!=
mStatus
&&
null
!=
mSwipeViewListener)
{
//說明有狀態(tài)發(fā)生變化
if
(mStatus
==
Status.CLOSE)
{
//關(guān)閉
mSwipeViewListener.onClose(this);
}
else
if
(mStatus
==
Status.OPEN)
{
//打開
mSwipeViewListener.onOpen(this);
}
else
if
(mStatus
==
Status.DRAGING)
{
//這里有2中情況,要么要打開,要么要關(guān)閉
if
(preStatus
==
Status.CLOSE)
{
//如果之前是關(guān)閉的,那么就是要打開
mSwipeViewListener.onStartOpen(this);
}
else
if
(preStatus
==
Status.OPEN)
{
//如果之前是打開,那么就是要關(guān)閉
mSwipeViewListener.onStartClose(this);
}
}
}
}
/**
*
獲取當前的狀態(tài)
*
*
@return
*/
private
Status
getCurrStatus()
{
int
left
=
mFrontView.getLeft();
if
(left
==
0)
{
return
Status.CLOSE;
}
else
if
(left
==
-mRange)
{
return
Status.OPEN;
}
return
Status.DRAGING;
}public
class
MainActivity
extends
AppCompatActivity
{
private
List<String>
mData
=
new
ArrayList<>();//數(shù)據(jù)集合
@Override
protected
void
onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
//獲取數(shù)據(jù),注意:Arrays.asList返回的并不是一個java.util.ArrayList,而是一個Arrays類的內(nèi)部類,該List實現(xiàn)是不能進行增刪操作的
//因此必須再包裝一下
mData
=
new
ArrayList<>(Arrays.asList(Constant.NAME));
ListView
listView
=
new
ListView(this);
listView.setAdapter(mAdapter);
setContentView(listView);
}
//自定義適配器
private
BaseAdapter
mAdapter
=
new
BaseAdapter()
{
//標記當前打開的SwipeLayout的集合
private
List<SwipeLayout>
mOpenItem
=
new
ArrayList<>();
@Override
public
int
getCount()
{
return
mData.size();
}
@Override
public
String
getItem(int
position)
{
return
mData.get(position);
}
@Override
public
long
getItemId(int
position)
{
return
position;
}
@Override
public
View
getView(final
int
position,
View
convertView,
ViewGroup
parent)
{
ViewHolder
holder
=
null;
if
(null
==
convertView)
{
holder
=
new
ViewHolder();
convertView
=
View.inflate(MainActivity.this,
R.layout.item_list,
null);
holder.mSwipeLayout
=
(SwipeLayout)
convertView;
holder.tvName
=
(TextView)
convertView.findViewById(R.id.tv_name);
holder.tvDel
=
(TextView)
convertView.findViewById(R.id.tv_del);
holder.tvEdit
=
(TextView)
convertView.findViewById(R.id.tv_edit);
convertView.setTag(holder);
}
else
{
holder
=
(ViewHolder)
convertView.getTag();
}
//設(shè)置側(cè)拉監(jiān)聽
holder.mSwipeLayout.setSwipeViewListener(getSwipeViewListener());
holder.tvName.setText(getItem(position));
holder.tvDel.setOnClickListener(new
View.OnClickListener()
{
@Override
public
void
onClick(View
v)
{
//刪除
mData.remove(position);
mAdapter.notifyDataSetChanged();
}
});
holder.tvEdit.setOnClickListener(new
View.OnClickListener()
{
@Override
public
void
onClick(View
v)
{
ToastUtils.showToast(MainActivity.this,"編輯");
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 微信ibeacon藍牙搖一搖周邊商場超市應(yīng)用案例
- 《鋼材知識專業(yè)培訓(xùn)》課件
- 張志敏英語課件Icanrunfa
- 福建省福州鼓樓區(qū)2025屆高考仿真卷語文試題含解析
- 湖北省葛洲壩中學(xué)2025屆高三第二次調(diào)研數(shù)學(xué)試卷含解析
- 上海市戲劇學(xué)院附中2025屆高考沖刺模擬語文試題含解析
- 2025屆浙江省“六市六校”聯(lián)盟高三3月份模擬考試數(shù)學(xué)試題含解析
- 2025屆黑龍江省佳木斯中學(xué)高三第六次模擬考試數(shù)學(xué)試卷含解析
- 2025屆安徽省屯溪第一中學(xué)高三沖刺模擬英語試卷含解析
- 2025屆廣東省河源市連平縣連平中學(xué)高考語文三模試卷含解析
- 2023年06月浙江杭州外國語學(xué)校招聘1人筆試歷年難、易錯考點試題含答案附詳解
- 2.PaleoScan詳細操作流程
- 【一例擴張型心肌病合并心力衰竭患者的個案護理】5400字【論文】
- 校園文化建設(shè)先進個人茍光武同志事跡材料
- 舞蹈教育專業(yè)建設(shè)調(diào)研報告
- 安徽六國化工股份有限公司磷石膏生態(tài)環(huán)境影響綜合整治及綠色發(fā)展項目環(huán)境影響報告書
- TOEFL閱讀100篇附答案
- 2023年高考四省聯(lián)考化學(xué)試題解析
- 醫(yī)院煎藥室-煎藥試題
- 古今醫(yī)學(xué)文獻研究方法與實踐(視頻課)知到章節(jié)答案智慧樹2023年浙江中醫(yī)藥大學(xué)
- 來曲唑超說明書用藥
評論
0/150
提交評論