day39 抽屉菜单以及下拉刷新framelayout实现

本文介绍了如何实现自定义抽屉菜单和基于Framelayout的下拉刷新功能。通过自定义View继承Framelayout,创建头布局并添加到自定义View中,然后获取并转化RecyclerView来实现下拉刷新。下拉刷新的各个状态包括默认、下拉刷新、释放刷新和正在刷新,通过回调接口进行网络请求并关闭下拉刷新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义抽屉菜单
package com.bwie.slidingmenu;

        import android.content.Context;
        import android.graphics.Color;
        import android.graphics.PointF;
        import android.util.AttributeSet;
        import android.util.Log;
        import android.view.MotionEvent;
        import android.view.View;
        import android.widget.FrameLayout;
        import android.widget.LinearLayout;

/**
 * 自定义抽屉
 * */
public class SlidingView extends FrameLayout {

    private LinearLayout contentLinear;//显示主界面
    private LinearLayout menuLinear;//显示菜单
    private int width = 400;//menu菜单宽度为400px
    private PointF lastPointF = new PointF();
    //上一次采集到的手指在屏幕上出发的点(X,Y)xy类型float

    public SlidingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init(){
        //初始化抽屉主界面布局
        contentLinear = new LinearLayout(getContext());
        FrameLayout.LayoutParams contentLp = new FrameLayout.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        contentLinear.setOrientation(LinearLayout.VERTICAL);
        contentLinear.setLayoutParams(contentLp);
        contentLinear.setBackgroundColor(Color.RED);
        addView(contentLinear);
        //初始化顶部菜单布局
        menuLinear = new LinearLayout(getContext());
        FrameLayout.LayoutParams menuLp = new FrameLayout.LayoutParams(
                width, LayoutParams.MATCH_PARENT);
        menuLp.leftMargin = -width;
        menuLinear.setOrientation(LinearLayout.VERTICAL);
        menuLinear.setLayoutParams(menuLp);
        menuLinear.setBackgroundColor(Color.GREEN);
        addView(menuLinear);
    }

    //向content中添加要显示的view
    public void addContent(View view){
        if (view == null)
            return;
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT
        );
        view.setLayoutParams(lp);
        contentLinear.addView(view);
    }
    //向menu中添加要显示的view
    public void addMenu(View view){
        if (view == null)
            return;
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT
        );
        view.setLayoutParams(lp);
        menuLinear.addView(view);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN){
            //手指按下
            //获取按下的点
            lastPointF.x = ev.getX();
            lastPointF.y = ev.getY();
        }else if (ev.getAction() == MotionEvent.ACTION_MOVE){
            //手指移动
            PointF pointF = new PointF(ev.getX(),ev.getY());
            //获取X轴滑动距离
            float distanceX = Math.abs(pointF.x - lastPointF.x);
            //获取Y轴滑动距离
            float distanceY = Math.abs(pointF.y - lastPointF.y);
            //区分垂直水平滑动方向
            if ((2*distanceY)>distanceX){
                //垂直滑动->分发事件
                return super.dispatchTouchEvent(ev);
            }
            if (distanceX>=10) {
                //获取菜单布局管理器
                FrameLayout.LayoutParams lp = (LayoutParams) menuLinear.getLayoutParams();
                //区分左右滑动方向
                if ((pointF.x-lastPointF.x)<0){
                    //从右向左
                    distanceX = -distanceX;
                }
                //可滑动区间内->更新leftmargin
                lp.leftMargin = (int) (lp.leftMargin + distanceX);
                if (lp.leftMargin > 0) {
                    lp.leftMargin = 0;
                    //重新布局
                    return true;
                }
                if (lp.leftMargin < -width) {
                    lp.leftMargin = -width;
                    return true;
                }
                menuLinear.requestLayout();
                lastPointF.x = pointF.x;
                lastPointF.y = pointF.y;
            }
        }else if (ev.getAction() == MotionEvent.ACTION_UP){
            //手指抬起
            FrameLayout.LayoutParams lp = (LayoutParams) menuLinear.getLayoutParams();
            if (lp.leftMargin<-width/2){
                lp.leftMargin = -width;
            }else {
                lp.leftMargin = 0;
            }
            menuLinear.requestLayout();
        }
        return super.dispatchTouchEvent(ev);
    }
}
public class MainActivity extends AppCompatActivity {

    private SlidingView slidingView;
    private View menuView;
    private View contentView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }

    private void init(){
        slidingView = findViewById(R.id.slidingmenu);
        menuView = LayoutInflater.from(this).inflate(R.layout.layout_menu,null);
        contentView = LayoutInflater.from(this).inflate(R.layout.layout_content,null);
        slidingView.addContent(contentView);
        slidingView.addMenu(menuView);
    }

}
自定义下拉刷新
  1. 基于自定义view上下啦刷新;
  2. 项目中使用上下啦刷新作用:刷新数据;数据分页;
  3. 基于系统framelayout编写上下拉刷新效果;
  4. 为什么基于framelayout->布局->framelayout中可添加子布局
    -> 可向framelayout中添加支持上下拉刷新的列表
  5. 实现步骤:
    (1)->创建PulltorefreshLayout自定义view->继承framelayout
    (2)->创建头布局->默认添加到自定义view中
    (3)->获取自定义view中包含的recyclerview->view
    (4)->获取的子view转化为具体类型->RecyclerView
    (5)->分发方法中拦截touch拦截
    ----->RecyclerView处于最上一条
    ----->手指由上向下滑动
    ----->下拉刷新->默认状态
    ------------->下拉刷新状态
    ------------->释放刷新状态
    ------------->正在刷新状态->回调接口->Activity中->网络请求->关闭下拉刷新
    ----->手指由下向上滑动->分发touch事件->保证Recyclerview可正常滑动
    ----->手指水平滑动->分发touch事件

自定义下拉刷新

import android.content.Context;
import android.graphics.Color;
import android.graphics.PointF;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * 自定义下拉刷新控件
 * */
public class PulltoRefreshLayout extends FrameLayout {

    private LinearLayout headLinear;//头布局的布局容器
    private RecyclerView rv;//FrameLayout中显示的列表
    private TextView headTv;
    private final static int PULL = 1;//下拉状态
    private final static int RELASE = 2;//释放刷新
    private final static int LOADING = 3;//正在刷新
    private final static int DEFAULT = 4;//默认
    private int mode = DEFAULT;//当前自定义控件的模式
    private PointF lastPointF = new PointF();//手指在屏幕中上一次触摸的点
    private boolean topFlag = true;//RecyclerView是否滑动到顶部标志
    private int height = 0;//headview头布局高度->下拉刷新临界值->添加高度的倍数作为临界值->增加滑动距离防止用户误触造成不必要刷新
    private LoadingListener loadingListener;//正在刷新回调接口

    public PulltoRefreshLayout( Context context,  AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    //初始化
    private void init(){
        headLinear = new LinearLayout(getContext());
        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT
        );
        headLinear.setLayoutParams(layoutParams);
        headLinear.setOrientation(LinearLayout.VERTICAL);
        addView(headLinear);
//         //循环遍历framelayout中全部子布局
//        for (int i = 0;i < getChildCount();i ++){
//            View view = getChildAt(i);
//            if (view instanceof RecyclerView){
//                rv = (RecyclerView) view;
//                break;
//            }
//        }
//        rv.addOnScrollListener(new RvListener());
    }

    public void setRV(RecyclerView rv){
        this.rv = rv;
        this.rv.setBackgroundColor(Color.WHITE);
        this.rv.addOnScrollListener(new RvListener());
        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        this.rv.setLayoutParams(lp);
        addView(rv);
    }

    //分发方法
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        if (ev.getAction() == MotionEvent.ACTION_DOWN){
            lastPointF.x = ev.getX();
            lastPointF.y = ev.getY();
        }else if (ev.getAction() == MotionEvent.ACTION_MOVE){
            PointF pointF = new PointF(ev.getX(),ev.getY());
            float disX = pointF.x - lastPointF.x;
            float disY = pointF.y - lastPointF.y;
            if (Math.abs(disX)>Math.abs(disY*2)){
                //水平滑动
                return super.dispatchTouchEvent(ev);
            }
            //RecyclerView未置顶
            if (!topFlag)
                return super.dispatchTouchEvent(ev);
            //RecyclerView在顶部->从下向上滑动->用户想浏览RecyclerView
            //->从上向下滑动->用户想下拉刷新
            //从下向上滑动
            if (disY < 0 && mode == DEFAULT){
                topFlag = false;//改变recyclerView置顶标志
                return super.dispatchTouchEvent(ev);
            }
            if (Math.abs(disY)>5) {
                //下拉刷新操作->下拉刷新逻辑处理
                selMode(disY);
            }
            return true;
        }else if (ev.getAction() == MotionEvent.ACTION_UP){
            if (mode == PULL || mode == DEFAULT){
                mode = DEFAULT;
//                headTv.setText("下拉刷新");
            }
            if (mode == RELASE)
                mode = LOADING;
            if (mode == LOADING && loadingListener !=null){
                loadingListener.loading();
                FrameLayout.LayoutParams lp = (LayoutParams) rv.getLayoutParams();
                lp.topMargin = height;
                headTv.setText("正在刷新");
                rv.requestLayout();
            }else {
                FrameLayout.LayoutParams lp = (LayoutParams) rv.getLayoutParams();
                lp.topMargin = 0;
                rv.requestLayout();
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    //下拉刷新选择状态方法
    private void selMode(float disY){
        FrameLayout.LayoutParams lp = (LayoutParams) rv.getLayoutParams();
        lp.topMargin += disY;
        if (lp.topMargin < 0)
            lp.topMargin = 0;
        if (lp.topMargin > 3*height)
            lp.topMargin = 3*height;
        //切换下拉状态->下拉刷新状态->0-(3*height-10);释放刷新(3*height-10  3*height)
        if (lp.topMargin > 0 && lp.topMargin < (3*height-10)){
            mode = PULL;
            headTv.setText("下拉刷新");
        }else if (lp.topMargin > (3*height-10)){
            mode = RELASE;
            headTv.setText("释放刷新");
        }
        rv.requestLayout();
        Log.e("####","selMode->"+mode);
    }

    //设置headView方法
    public void addHeadView(View view){
        view.measure(0,0);
        height = view.getMeasuredHeight();
        view.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                view.getMeasuredHeight()));
        headLinear.addView(view);
        headTv = view.findViewById(R.id.tv);
    }

    //设置下拉刷新监听方法
    public void setLoadingListener(LoadingListener loadingListener){
        this.loadingListener = loadingListener;
    }

    //完成方法->加载完网络请求数据->关闭下拉刷新
    public void complate(){
        mode = DEFAULT;
        topFlag = true;
        FrameLayout.LayoutParams lp = (LayoutParams) rv.getLayoutParams();
        lp.topMargin = 0;
        rv.requestLayout();
    }

    //监听RecyclerView滑动位置->是否滑动到顶部
    private class RvListener extends RecyclerView.OnScrollListener{
        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            Log.e("####","RvListener->onScrolled");
            if (!recyclerView.canScrollVertically(-1)&&!topFlag){
                Log.e("####","RvListener->onScrolled->滑动到顶部");
                topFlag = true;
            }
        }
    }

    //正在刷新回调监听器
    public interface LoadingListener{
        void loading();
    }

}

适配器

public class MainAdapter extends RecyclerView.Adapter<MainAdapter.MainVH>{

    private List<String>list;
    public MainAdapter(List<String>list){
        this.list = list;
    }

    @NonNull
    @Override
    public MainVH onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_main,viewGroup,false);
        return new MainVH(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull MainVH mainVH, int i) {
        mainVH.tv.setText(list.get(i));
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    class MainVH extends RecyclerView.ViewHolder{
        TextView tv;
        public MainVH(@NonNull View itemView) {
            super(itemView);
            tv = itemView.findViewById(R.id.main_tv);
        }
    }

}

activity

public class MainActivity extends AppCompatActivity implements PulltoRefreshLayout.LoadingListener {

    private List<String>list = new ArrayList<>();
    private PulltoRefreshLayout pullLayout;
    private RecyclerView rv;
    private View headView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        init();
    }

    private void init(){
        pullLayout = findViewById(R.id.main_pull);
        rv = new RecyclerView(this);
        pullLayout.setRV(rv);
        headView = LayoutInflater.from(this).inflate(R.layout.layout_head,null);
        pullLayout.addHeadView(headView);
        pullLayout.setLoadingListener(this);
        LinearLayoutManager manager = new LinearLayoutManager(this);
        manager.setOrientation(LinearLayoutManager.VERTICAL);
        rv.setLayoutManager(manager);
        rv.setAdapter(new MainAdapter(list));
    }

    private void initData(){
        for (int i = 0;i < 100;i ++){
            list.add("item:"+i);
        }
    }

    @Override
    public void loading() {
        new Thread(){

            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        pullLayout.complate();
                    }
                });
            }
        }.start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值