Android-PhotoView框架的使用

一、背景

  • 收到了设计小姐姐的一张设计图,如下所示
  • 需求分析,一个可以横纵向四个方向滚动的列表
  • 注意:文章穿插太多代码,最好目录跳转查看。文字部分为主要思想,代码可略过。
    在这里插入图片描述

二、开始敲代码

方案1 自定义粗糙辣鸡儿View

  • 不考虑横纵向都可以滚动的要求的话,这个图一看就像是一个RecyclerView,然后通过LayoutManager(GridManager,表格布局)控制其布局的显示方式。
  • 接着考虑滚动的问题,RecycleView自己可以滚动,假如设置为纵向滚动,那么我们需要在RecyclerView监测到横向滚动的时候拦截事件。
  • 实现方式:使用RelativeLayout 嵌套一个RecyclerView 。根据事件分发机制,当监测到事件时,任务首先层层向下传递,没人拦截,就传给最底层View。此时监测到横向滚动的时候,我们在父布局中onInterceptTouchEvent拦截事件,返回true,不再向下传递。由父布局直接处理。
  • 问题:基础效果实现了,但是用户体验度会非常差
    1.如此实验的界面,没有考虑到惯性滑动,用户滑动多少距离就移动多少距离,会觉得很卡顿;
    解决办法:手势识别的onfling方法中进行处理,可以参考PhotoView 解析一文
    2、同一时间只能横向移动或纵向移动,必须等一个行为停止之后,另一个才会被响应;
package com.snap.awesomeserial.ui.widget;
public class FullInformationView extends RelativeLayout {
   

    /**
     * 手指按下时的位置
     */
    private float mStartX = 0;
    /**
     * 滑动时和按下时的差值
     */
    private float mMoveOffsetX = 0;
    /**
     * 展示数据时使用的RecycleView
     */
    private RecyclerView mRecyclerView;
    /**
     * RecycleView的Adapter
     */
    private FullInformationAdapter mAdapter;
    private Context context;
    /**
     * 触发拦截手势的最小值
     */
    private int mTriggerMoveDis = 30;
    private float currentOffsetX;
    private ScrollListener horizontalListener;
    private ScrollListener verticalListener;


    public FullInformationView(Context context) {
   
        this(context, null);
    }

    public FullInformationView(Context context, AttributeSet attrs) {
   
        this(context, attrs, 0);
    }

    public FullInformationView(Context context, AttributeSet attrs, int defStyleAttr) {
   
        super(context, attrs, defStyleAttr);
        this.context = context;
    }

    private void initView() {
   
        LinearLayout linearLayout = new LinearLayout(getContext());
        linearLayout.setOrientation(LinearLayout.VERTICAL);
        linearLayout.addView(createMoveRecyclerView());
        addView(linearLayout, new LayoutParams(LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
    }


    public void setHorizontalListener(ScrollListener horizontalListener) {
   
        this.horizontalListener = horizontalListener;
    }

    public void setVerticalListener(ScrollListener verticalListener) {
   
        this.verticalListener = verticalListener;
    }

    /**
     * 创建数据展示布局
     **/
    private View createMoveRecyclerView() {
   
        FrameLayout linearLayout = new FrameLayout(getContext());
        mRecyclerView = new RecyclerView(getContext());
        GridLayoutManager layoutManager = new GridLayoutManager(context, 12, GridLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(layoutManager);
        if (null != mAdapter) {
   
            mRecyclerView.setAdapter(mAdapter);
        }
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
   
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
   
                //显示区域的高度。
                int extent = mRecyclerView.computeVerticalScrollExtent();
                //整体的高度,注意是整体,包括在显示区域之外的。
                int range = mRecyclerView.computeVerticalScrollRange();
                //已经向下滚动的距离,为0时表示已处于顶部。
                int offset = mRecyclerView.computeVerticalScrollOffset();
                float percent = offset / ((range - extent) * 1f);
                verticalListener.onScroll(percent);
            }
        });

        linearLayout.addView(mRecyclerView, new LayoutParams(LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT));
        return linearLayout;
    }

    /**
     * 设置adapter
     *
     * @param adapter
     */
    public void setAdapter(FullInformationAdapter adapter) {
   
        mAdapter = adapter;
        initView();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
   
        switch (ev.getAction()) {
   
            case MotionEvent.ACTION_DOWN:
                mStartX = ev.getX();
                break;
            case MotionEvent.ACTION_UP:
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = (int) Math.abs(ev.getX() - mStartX);
                //水平移动大于30触发拦截
                if (offsetX > mTriggerMoveDis) {
   
                    return true;
                } else {
   
                    return false;
                }
            default:
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
   
        float totalX = (getWidth() - AutoSizeUtils.dp2px(context, 1740));
        switch (event.getAction()) {
   
            case MotionEvent.ACTION_DOWN:
                return true;
            case MotionEvent.ACTION_UP:
                currentOffsetX = (mStartX - event.getX()) + currentOffsetX;
                if (currentOffsetX 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值