android布局置顶_Android自定义View(四)侧滑布局

利用Scroller来写一个侧滑布局效果如下:

ezgif-5-2511a3329a.gif

1.自定义一个Viewgroup在构造方法初始化参数mScroller = new Scroller(context);        //滑动临界值

ViewConfiguration viewConfiguration = ViewConfiguration.get(context);

mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(viewConfiguration);

2.在onMeasure方法中测量子孩子大小if (!mIsMeasure) {            for (int i = 0; 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 

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 

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 

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 mDatas;    private DeleteView mDeleteView;    private DeleteView mOpenView;    public DeleteAdapter(List list) {

mDatas = list;

}    public void setData(List 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());

}

}

}

作者:xlh__

链接:https://www.jianshu.com/p/34e756508549

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值