Android 刷卡使用 SwipeFlingAdapterView 库缩放图像视图

Posted

技术标签:

【中文标题】Android 刷卡使用 SwipeFlingAdapterView 库缩放图像视图【英文标题】:Android swipe card with pinch to zoom imageview using SwipeFlingAdapterView library 【发布时间】:2016-09-03 05:46:24 【问题描述】:

我正在使用 this 库实现 swipe cardpinch to zoom 功能,当我只使用 image view 时它工作正常意味着滑动工作正常但我想要像库和 pinch to zoom 这样的滑动功能所以我添加了 TouchImageView 类,其中只有 pinch to zoom 工作但滑动功能不起作用。那么您能否帮我解决这个问题或建议我使用swipe cardpinch to zoom 可能的任何替代库。 以下是我的活动

    public class MainActivity extends AppCompatActivity

    private SwipeFlingAdapterView flingContainer;
    public static ArrayList<SwipModel> al;
    public SwipViewAdapter swipViewAdapter;
    private SwipModel swipModel;
    private Uri uri;


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


        getId();
        setSwipeCard();

    

    private void getId() 
        flingContainer = (SwipeFlingAdapterView) findViewById(R.id.frame);
    

    private void setSwipeCard() 

        uri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() + "/drawable/picture1");

        swipModel = new SwipModel();

        al = new ArrayList<>();
        swipModel.setCardImageDrawable(uri);
        al.add(swipModel);


        swipViewAdapter = new SwipViewAdapter(getApplicationContext(), al);

        flingContainer.setAdapter(swipViewAdapter);
        flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener() 
            @Override
            public void removeFirstObjectInAdapter() 
                // this is the simplest way to delete an object from the Adapter (/AdapterView)
                Log.d("LIST", "removed object!");
//                al.remove(0);
//                swipViewAdapter.notifyDataSetChanged();
            

            @Override
            public void onLeftCardExit(Object dataObject) 
                //Do something on the left!
                //You also have access to the original object.
                //If you want to use it just cast it (String) dataObject
//                makeToast(MainActivity.this, "Left!");
            

            @Override
            public void onRightCardExit(Object dataObject) 
//                makeToast(MainActivity.this, "Right!");
            

            @Override
            public void onAdapterAboutToEmpty(int itemsInAdapter) 
                // Ask for more data here
//                al = new ArrayList<>();
//                swipModel.setCardImageDrawable(uri);
//                al.add(swipModel);
            

            @Override
            public void onScroll(float scrollProgressPercent) 
                View view = flingContainer.getSelectedView();
            
        );


        // Optionally add an OnItemClickListener.
        flingContainer.setOnItemClickListener(new SwipeFlingAdapterView.OnItemClickListener() 
            @Override
            public void onItemClicked(int itemPosition, Object dataObject) 

            
        );
        

这里是activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context="com.example.android.swipecardtesting.MainActivity">

    <com.lorentzos.flingswipe.SwipeFlingAdapterView
        android:id="@+id/frame"
        android:background="#ffeee9e2"
        android:layout_
        android:layout_
        app:rotation_degrees="15.5"
        tools:context=".MyActivity"
        android:layout_centerInParent="true"
        />

</RelativeLayout>

这是我的Adapter

    public class SwipViewAdapter extends BaseAdapter 

    public static ArrayList<SwipModel> list;
    Context context;
    private LayoutInflater l_Inflater;
    public static ViewHolder holder;

    public SwipViewAdapter(Context mContext, ArrayList<SwipModel> al) 
        this.context = mContext;
        list = al;
        l_Inflater = LayoutInflater.from(context);
    

    @Override
    public int getCount() 
        return list.size();
    

    @Override
    public Object getItem(int i) 
        return i;
    

    @Override
    public long getItemId(int i) 
        return i;
    

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) 
        if (view == null) 
            holder = new ViewHolder();

            l_Inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = l_Inflater.inflate(R.layout.swip_item, viewGroup, false);


            holder.ivZoomable = (TouchImageView) view.findViewById(R.id.ivZoomable);

            view.setTag(holder);
        



        holder.ivZoomable.setImageURI(list.get(i).getCardImageDrawable());


        return view;
    

    public static class ViewHolder 
        public static TouchImageView ivZoomable;
    

还有我的TouchImageView 班级

public class TouchImageView extends ImageView 

    Matrix matrix;

    // We can be in one of these 3 states
    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    int mode = NONE;

    // Remember some things for zooming
    PointF last = new PointF();
    PointF start = new PointF();
    float minScale = 1f;
    float maxScale = 3f;
    float[] m;

    int viewWidth, viewHeight;
    static final int CLICK = 3;
    public static float saveScale = 1f;
    protected float origWidth, origHeight;
    int oldMeasuredWidth, oldMeasuredHeight;

    ScaleGestureDetector mScaleDetector;

    Context context;

    public TouchImageView(Context context) 
        super(context);
        sharedConstructing(context);
    

    public TouchImageView(Context context, AttributeSet attrs) 
        super(context, attrs);
        sharedConstructing(context);
    

    private void sharedConstructing(Context context) 
        super.setClickable(true);
        this.context = context;
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        matrix = new Matrix();
        m = new float[9];
        setImageMatrix(matrix);
        setScaleType(ScaleType.MATRIX);

        setOnTouchListener(new OnTouchListener() 

            @Override
            public boolean onTouch(View v, MotionEvent event) 
                mScaleDetector.onTouchEvent(event);
                PointF curr = new PointF(event.getX(), event.getY());

                switch (event.getAction()) 
                    case MotionEvent.ACTION_DOWN:
                        last.set(curr);
                        start.set(last);
                        mode = DRAG;
                        break;

                    case MotionEvent.ACTION_MOVE:
                        if (mode == DRAG) 
                            float deltaX = curr.x - last.x;
                            float deltaY = curr.y - last.y;
                            float fixTransX = getFixDragTrans(deltaX, viewWidth,
                                    origWidth * saveScale);
                            float fixTransY = getFixDragTrans(deltaY, viewHeight,
                                    origHeight * saveScale);
                            matrix.postTranslate(fixTransX, fixTransY);
                            fixTrans();
                            last.set(curr.x, curr.y);
                        
                        break;

                    case MotionEvent.ACTION_UP:
                        mode = NONE;
                        int xDiff = (int) Math.abs(curr.x - start.x);
                        int yDiff = (int) Math.abs(curr.y - start.y);
                        if (xDiff < CLICK && yDiff < CLICK)
                            performClick();
                        break;

                    case MotionEvent.ACTION_POINTER_UP:
                        mode = NONE;
                        break;
                

                setImageMatrix(matrix);
                invalidate();
                return true; // indicate event was handled
            

        );
    

    public void setMaxZoom(float x) 
        maxScale = x;
    


    private class ScaleListener extends
            ScaleGestureDetector.SimpleOnScaleGestureListener 
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) 
            mode = ZOOM;
            return true;
        

        @Override
        public boolean onScale(ScaleGestureDetector detector) 
            float mScaleFactor = detector.getScaleFactor();
            float origScale = saveScale;
            saveScale *= mScaleFactor;

            if(saveScale<1)
            
                Log.e("saveScale is ","executing =====> "+saveScale);
                SwipViewAdapter.ViewHolder.imageView.setVisibility(VISIBLE);
                SwipViewAdapter.ViewHolder.ivZoomable.setVisibility(GONE);
            
            else
            
                Log.e("saveScale is ","executing =====> "+saveScale);
                SwipViewAdapter.ViewHolder.imageView.setVisibility(GONE);
                SwipViewAdapter.ViewHolder.ivZoomable.setVisibility(VISIBLE);
            



            if (saveScale > maxScale) 
                saveScale = maxScale;
                mScaleFactor = maxScale / origScale;
            
            else if (saveScale < minScale) 
                saveScale = minScale;
                mScaleFactor = minScale / origScale;
            

            if (origWidth * saveScale <= viewWidth
                    || origHeight * saveScale <= viewHeight)
                matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
                        viewHeight / 2);
            else
                matrix.postScale(mScaleFactor, mScaleFactor,
                        detector.getFocusX(), detector.getFocusY());

            fixTrans();
            return true;
        
    

    void fixTrans() 
        matrix.getValues(m);
        float transX = m[Matrix.MTRANS_X];
        float transY = m[Matrix.MTRANS_Y];

        float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
        float fixTransY = getFixTrans(transY, viewHeight, origHeight
                * saveScale);

        if (fixTransX != 0 || fixTransY != 0)
            matrix.postTranslate(fixTransX, fixTransY);
    

    float getFixTrans(float trans, float viewSize, float contentSize) 
        float minTrans, maxTrans;

        if (contentSize <= viewSize) 
            minTrans = 0;
            maxTrans = viewSize - contentSize;
         else 
            minTrans = viewSize - contentSize;
            maxTrans = 0;
        

        if (trans < minTrans)
            return -trans + minTrans;
        if (trans > maxTrans)
            return -trans + maxTrans;
        return 0;
    

    float getFixDragTrans(float delta, float viewSize, float contentSize) 
        if (contentSize <= viewSize) 
            return 0;
        
        return delta;
    

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewWidth = MeasureSpec.getSize(widthMeasureSpec);
        viewHeight = MeasureSpec.getSize(heightMeasureSpec);

        //
        // Rescales image on rotation
        //
        if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
                || viewWidth == 0 || viewHeight == 0)
            return;
        oldMeasuredHeight = viewHeight;
        oldMeasuredWidth = viewWidth;

        if (saveScale == 1) 
            // Fit to screen.
            float scale;

            Drawable drawable = getDrawable();
            if (drawable == null || drawable.getIntrinsicWidth() == 0
                    || drawable.getIntrinsicHeight() == 0)
                return;
            int bmWidth = drawable.getIntrinsicWidth();
            int bmHeight = drawable.getIntrinsicHeight();

            Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);

            float scaleX = (float) viewWidth / (float) bmWidth;
            float scaleY = (float) viewHeight / (float) bmHeight;
            scale = Math.min(scaleX, scaleY);
            matrix.setScale(scale, scale);

            // Center the image
            float redundantYSpace = (float) viewHeight
                    - (scale * (float) bmHeight);
            float redundantXSpace = (float) viewWidth
                    - (scale * (float) bmWidth);
            redundantYSpace /= (float) 2;
            redundantXSpace /= (float) 2;

            matrix.postTranslate(redundantXSpace, redundantYSpace);

            origWidth = viewWidth - 2 * redundantXSpace;
            origHeight = viewHeight - 2 * redundantYSpace;
            setImageMatrix(matrix);
        
        fixTrans();
    


【问题讨论】:

也许这可以帮助你:***.com/questions/11672210/… @Abbas 感谢您的回复。我按你说的试过了,还是不行。 尝试从onTouch返回false,如果saveScale != 1,则应该传递触摸事件。 提示:你需要在 TouchImageView 中的 onTouchEvent 返回 false 才能让滑动生效。 【参考方案1】:

当只有一个指针向下时,在 TouchImageView 类中的 OnTouchListener.onTouch() 中返回 false,如下所示:

@Override
public boolean onTouch(View v, MotionEvent event) 

    // Touch logic here

    return event.getPointerCount() > 1;

这种方式捏到缩放只会在两个指针存在时消耗触摸事件(需要执行捏合)。

更新:

扩展SwipeFlingAdapterView 类并覆盖onInterceptTouchEvent() 方法,就像在这里完成的那样:Using onInterceptTouchEvent

然后你可以像这样拦截指向图像视图的触摸事件:

public void onInterceptTouchEvent(MotionEvent event) 
    if(event.getPointerCount() == 1) 
        onTouchEvent(event);
    
    return false;

更多关于触摸拦截的文档:https://developer.android.com/training/gestures/viewgroup.html

希望对你有帮助!

【讨论】:

感谢您的帮助,我将您的代码放在了 TouchImageView 类的 onTouch 中,但滑动功能仍然不起作用,只有捏缩放可以工作,但实际上我还需要捏缩放和滑动功能。跨度>

以上是关于Android 刷卡使用 SwipeFlingAdapterView 库缩放图像视图的主要内容,如果未能解决你的问题,请参考以下文章

Android:刷卡后点击在回收站项目上不起​​作用

耳机电话插孔信用卡刷卡与浏览器应用程序

使用 Sveltekit 刷卡:没有“刷卡”

如何在 IOS 中使用 IDTECH 刷卡器读取信用卡信息?

使用 ASP.NET MVC 进行信用卡支付(有卡、刷卡)

我试图捕捉刷卡的输入,但我被困在使用 C# Windows 窗体