Android自定義View(四)側滑佈局
利用Scroller來寫一個側滑佈局效果如下:
1.自定義一個Viewgroup在構造方法初始化引數
mScroller = new Scroller(context);
//滑動臨界值
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(viewConfiguration);
2.在onMeasure方法中測量子孩子大小
if (!mIsMeasure) {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
measureChild(view, widthMeasureSpec, heightMeasureSpec);
}
mIsMeasure = true;
}
3.在onLayout佈局中初始化子孩子的位置裡面有三個view分別是文字內容,置頂以及刪除
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
if (i == 0) {
mTextWidth = view.getMeasuredWidth();
view.layout(0, 0, mTextWidth, view.getMeasuredHeight());
} else if (i == 1) {
//置頂文字的寬度
mStickWidth = view.getMeasuredWidth();
view.layout(mTextWidth, 0, mTextWidth + mStickWidth, view.getMeasuredHeight());
} else if (i == 2) {
//刪除文字的寬度
mDeleteWidth = view.getMeasuredWidth();
view.layout(mTextWidth + mStickWidth, 0, mTextWidth + mStickWidth + mDeleteWidth, view.getMeasuredHeight());
}
}
}
4.在onInterceptTouchEvent方法中處理滑動事件,如果是橫向滑動我們就攔截事件自己去處理事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = (int) ev.getRawX();
break;
case MotionEvent.ACTION_MOVE:
mMovex = (int) ev.getRawX();
float diff = Math.abs(mMovex - mDownX);
// 當手指拖動值大於TouchSlop值時,認為應該進行滾動,攔截子控制元件的事件
mLastMove = mMovex;
if (diff > mTouchSlop) {
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
5.在onTouchEvent方法中處理滑動事件,用ScrollBy方法來移動控制元件,移動過程中對移動範圍進行限制
move事件中:
mMovex = (int) event.getX();
scrollBy(mLastMove - mMovex, 0);
if (getScrollX() <= 0) {
scrollTo(0, 0);
return true;
}
if (getScrollX() >= mDeleteWidth + mStickWidth) {
scrollTo(mDeleteWidth + mStickWidth, 0);
return true;
}
mLastMove = mMovex;
當手指抬起的時候根據移動的位置來判斷是否是開啟還是關閉getScrollX()方法可以得到移動的x值,大於置頂和刪除文字寬度一半時就是開啟狀態否則就是關閉
if (getScrollX() >= mDeleteWidth) {//open
dx = mDeleteWidth + mStickWidth - getScrollX();
if (mOnStateChangeListener != null) {
mOnStateChangeListener.onOpen(this);
}
} else {//close
dx = 0 - getScrollX();
mOnStateChangeListener.onClose(this);
}
mScroller.startScroll(getScrollX(), 0, dx, 0);
invalidate();
6.在配合Recycleview使用的時候要注意的地方:
在onTouchEvent方法中move事件要請求父控制元件不要攔截否則收不到up事件
//請求父容器不要攔截事件
getParent().requestDisallowInterceptTouchEvent(true);
在側滑時一個條目時其他條目都要關閉這裡利用adapter進行對當前滑動條目的記錄和已經開啟的條目記錄,然後在move的時候進行判斷
case MotionEvent.ACTION_MOVE:
if (getAdapter().getOpenView() != null && getAdapter().getOpenView() != this) {
getAdapter().getOpenView().close();
getAdapter().setOpenView(null);
return true;
}
if (getAdapter().getCurrentDeleteView() !=null && getAdapter().getCurrentDeleteView() != this) {
return true;
}
完整程式碼:
public class DeleteView extends ViewGroup {
private Scroller mScroller;
private int mDownX;
private int mMovex;
private int mTouchSlop;
private boolean mIsMeasure = false;
private int mTextWidth;
private int mStickWidth;
private int mDeleteWidth;
private int mLastMove;
public DeleteView(Context context) {
this(context, null);
}
public DeleteView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
//滑動臨界值
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(viewConfiguration);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!mIsMeasure) {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
measureChild(view, widthMeasureSpec, heightMeasureSpec);
}
mIsMeasure = true;
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
if (i == 0) {
mTextWidth = view.getMeasuredWidth();
view.layout(0, 0, mTextWidth, view.getMeasuredHeight());
} else if (i == 1) {
mStickWidth = view.getMeasuredWidth();
view.layout(mTextWidth, 0, mTextWidth + mStickWidth, view.getMeasuredHeight());
} else if (i == 2) {
mDeleteWidth = view.getMeasuredWidth();
view.layout(mTextWidth + mStickWidth, 0, mTextWidth + mStickWidth + mDeleteWidth, view.getMeasuredHeight());
}
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = (int) ev.getRawX();
break;
case MotionEvent.ACTION_MOVE:
mMovex = (int) ev.getRawX();
float diff = Math.abs(mMovex - mDownX);
// 當手指拖動值大於TouchSlop值時,認為應該進行滾動,攔截子控制元件的事件
mLastMove = mMovex;
if (diff > mTouchSlop) {
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
if (getAdapter().getOpenView() != null && getAdapter().getOpenView() != this) {
getAdapter().getOpenView().close();
getAdapter().setOpenView(null);
return true;
}
if (getAdapter().getCurrentDeleteView() !=null && getAdapter().getCurrentDeleteView() != this) {
return true;
}
getAdapter().setCurrentDeleteView(this);
//請求父容器不要攔截事件
getParent().requestDisallowInterceptTouchEvent(true);
mMovex = (int) event.getX();
scrollBy(mLastMove - mMovex, 0);
if (getScrollX() <= 0) {
scrollTo(0, 0);
return true;
}
if (getScrollX() >= mDeleteWidth + mStickWidth) {
scrollTo(mDeleteWidth + mStickWidth, 0);
return true;
}
mLastMove = mMovex;
break;
case MotionEvent.ACTION_UP:
LogUtils.LogE("up");
int dx = 0;
if (getScrollX() >= mDeleteWidth) {//open
dx = mDeleteWidth + mStickWidth - getScrollX();
if (mOnStateChangeListener != null) {
mOnStateChangeListener.onOpen(this);
}
} else {//close
dx = 0 - getScrollX();
mOnStateChangeListener.onClose(this);
}
mScroller.startScroll(getScrollX(), 0, dx, 0);
invalidate();
getAdapter().setCurrentDeleteView(null);
break;
}
return true;
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}
public interface onStateChangeListener {
void onOpen(DeleteView deleteView);
void onClose(DeleteView deleteView);
}
private onStateChangeListener mOnStateChangeListener;
public void setOnStateChangeListener(onStateChangeListener onStateChangeListener) {
mOnStateChangeListener = onStateChangeListener;
}
public void open() {
scrollTo(mStickWidth + mDeleteWidth, 0);
}
public void close() {
scrollTo(0, 0);
}
/**
* 得到介面卡
*
* @return
*/
private DeleteAdapter getAdapter() {
return (DeleteAdapter) ((RecyclerView) getParent()).getAdapter();
}
Adapter程式碼:
public class DeleteAdapter extends RecyclerView.Adapter {
private List<CartModel> mDatas;
private DeleteView mDeleteView;
private DeleteView mOpenView;
public DeleteAdapter(List<CartModel> list) {
mDatas = list;
}
public void setData(List<CartModel> list) {
mDatas = list;
notifyDataSetChanged();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_delete, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
MyHolder myHolder = (MyHolder) holder;
myHolder.setItem(position);
((DeleteView) holder.itemView).setOnStateChangeListener(new DeleteView.onStateChangeListener() {
@Override
public void onOpen(DeleteView deleteView) {
mOpenView = deleteView;
}
@Override
public void onClose(DeleteView deleteView) {
}
});
myHolder.delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(),"刪除"+position,Toast.LENGTH_SHORT).show();
mDatas.remove(position);
getOpenView().close();
notifyDataSetChanged();
}
});
myHolder.stick.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CartModel cartModel = mDatas.get(position);
Toast.makeText(v.getContext(),"置頂"+position,Toast.LENGTH_SHORT).show();
mDatas.remove(cartModel);
mDatas.add(0,cartModel);
getOpenView().close();
notifyDataSetChanged();
}
});
}
/**
* 得到當前滑動的view
*
* @return
*/
public DeleteView getCurrentDeleteView() {
return mDeleteView;
}
/**
* 得到當前滑動的view
*
* @return
*/
public void setCurrentDeleteView(DeleteView deleteView) {
this.mDeleteView = deleteView;
}
public DeleteView getOpenView() {
return mOpenView;
}
public void setOpenView(DeleteView openView) {
mOpenView = openView;
}
@Override
public int getItemCount() {//加的一是腳步局
return mDatas.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView title;
TextView stick;
TextView delete;
public MyHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.tv_title);
stick = itemView.findViewById(R.id.tv_stick);
delete = itemView.findViewById(R.id.tv_delete);
}
public void setItem(int position) {
CartModel cartModel = mDatas.get(position);
title.setText(cartModel.getName());
}
}
}
相關文章
- 自定義View:側滑選單實現View
- 自定義View:側滑選單動畫實現View動畫
- 自定義view——仿酷狗的側滑選單View
- Android 自定義View 滑動解鎖AndroidView
- 【朝花夕拾】Android自定義View篇之(十一)View的滑動,彈性滑動與自定義PagerViewAndroidView
- Android自定義View實現流式佈局(熱門標籤效果)AndroidView
- Android 自定義氣泡佈局Android
- android 滑動刪除的listview(自定義view)AndroidView
- objc系列譯文(3.3):自定義Collection View佈局OBJView
- 自定義ViewGroup,實現Android的側滑選單ViewAndroid
- 深入解析Android的自定義佈局Android
- Android開發自定義View之滑動按鈕與自定義屬性AndroidView
- 自定義RecyclerView實現側滑刪除View
- Android開發筆記(一百二十)兩種側滑佈局Android筆記
- Android自定義View:View(二)AndroidView
- 3個自定義view佈局:矩形TextView,圓形進度條,圓環viewTextView
- android view 自定義viewgroup 例項--螢幕滑動AndroidView
- android自定義佈局——城市選擇介面Android
- Android 自定義viewAndroidView
- Android: 自定義ViewAndroidView
- android自定義View(2):實現百分比自適應佈局AndroidView
- Android 自定義View:處理事件分發(四)AndroidView事件
- UICollectionView自定義佈局(二)UIView
- UICollectionView自定義佈局(一)UIView
- Android GUI之View佈局AndroidGUIView
- AndroidDrawerLayout+fragment佈局實現左右側滑AndroidFragment
- Android自定義View整合AndroidView
- 【朝花夕拾】Android自定義View篇之(四)自定義View的三種實現方式及自定義屬性詳解AndroidView
- Android自定義view-自繪ViewAndroidView
- 谷歌開發者工具自定義佈局谷歌
- Flutter自定義佈局-CustomMultiChildLayoutFlutter
- android自定義view(自定義數字鍵盤)AndroidView
- android自定義View&自定義ViewGroup(下)AndroidView
- android自定義View&自定義ViewGroup(上)AndroidView
- css佈局之左側固定右側自適應佈局CSS
- Android XML佈局報錯:android/view/View$OnUnhandledKeyEventListenerAndroidXMLView
- 重拾Android自定義ViewAndroidView
- Android自定義view詳解AndroidView