Android Studio安卓开发ZoomImageView图片放大缩小与ViewPager冲突问题

Android多点触控之ZoomImageView完全解析 ZoomImageView是一个类似photoview的图片预览控件,实现了对图片的手势放大缩小平移,以及双击放大缩小解决和viewpager滑动冲突等功能,主要是通过GestureDetector,Matrix相关api以及对事件的ontouch处理实现的,这个代码网上能搜索到很多,但是因为注释少所以要完全读懂有些困难,于是本人整理了一段时间,写了一个完整的注释版本,基本每行代码都做到了讲解,大家 阅读详情

        最近有个需求是做一个点击图片放大放小功能,然后参考了自定义ZoomImageView这个类来做,但是做到后面发现缩小之后,滑动的时候会与ViewPager冲突,他会滑到下一页,我肯定是希望缩小滑动的时候,应该靠近边界了再滑动到下一页,网上找了很多方法,有说用getParent().requestDisallowInterceptTouchEvent(true);这个拦截,但我感觉不是明智之举。

我先展示我做的效果:

那怎么去做这个ViewPager图片放大缩小功能了,代码如下:

首先参考https://blog.csdn.net/qq_35983486/article/details/125314603他的ZoomImageView类,写的还可以,我运行了,挺丝滑的,因为有惯性滑动,还有一些缩到最小的时候,弹一下的细节功能,他的代码如下:

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
import android.widget.OverScroller;


@SuppressLint("AppCompatCustomView")
public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener {

    private boolean mIsOneLoad = true;

    //初始化的比例,也就是最小比例
    private float mInitScale;
    //图片最大比例
    private float mMaxScale;
    //双击能达到的最大比例
    private float mMidScale;

    private Matrix mScaleMatrix;
    //捕获用户多点触控
    private ScaleGestureDetector mScaleGestureDetector;

    //移动
    private GestureDetector gestureDetector;

    //双击
    private boolean isEnlarge = false;//是否放大
    private ValueAnimator mAnimator; //双击缩放动画

    //滚动
    private OverScroller scroller;
    private int mCurrentX, mCurrentY;
    private ValueAnimator translationAnimation; //惯性移动动画

    //单击
    private OnClickListener onClickListener;//单击监听

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

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

    public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //记住,一定要把ScaleType设置成ScaleType.MATRIX,否则无法缩放
        setScaleType(ScaleType.MATRIX);

        scroller = new OverScroller(context);
        mScaleMatrix = new Matrix();
        //手势缩放
        mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                scale(detector);
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                scaleEnd(detector);
            }
        });

        //滑动和双击监听
        gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, final float distanceX, final float distanceY) {
                //滑动监听
                onTranslationImage(-distanceX, -distanceY);
                return true;
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                //双击监听
                onDoubleDrowScale(e.getX(), e.getY());
                return true;
            }


            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                //移动之后,松开手指产生的惯性,会触发以下方法
                mCurrentX = (int) e2.getX();
                mCurrentY = (int) e2.getY();

                RectF rectF = getMatrixRectF();
                if (rectF == null) {
                    return false;
                }
                //startX为当前图片左边界的x坐标
                int startX = mCurrentX;
                int startY = mCurrentY;
                int minX = 0, maxX = 0, minY = 0, maxY = 0;
                int vX = Math.round(velocityX);
                int vY = Math.round(velocityY);

                maxX = Math.round(rectF.width());
                maxY = Math.round(rectF.height());

                if (startX != maxX || startY != maxY) {
                    //调用fling方法,然后我们可以通过调用getCurX和getCurY来获得当前的x和y坐标
                    //这个坐标的计算是模拟一个惯性滑动来计算出来的,我们根据这个x和y的变化可以模拟
                    //出图片的惯性滑动
                    scroller.fling(startX, startY, vX, vY, 0, maxX, 0, maxY, maxX, maxY);
                }

                if (translationAnimation != null && translationAnimation.isStarted())
                    translationAnimation.end();

                translationAnimation = ObjectAnimator.ofFloat(0, 1);
                translationAnimation.setDuration(500);
                translationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        if (scroller.computeScrollOffset()) {
                            //获得当前的x坐标
                            int newX = scroller.getCurrX();
                            int dx = newX - mCurrentX;
                            mCurrentX = newX;
                            //获得当前的y坐标
                            int newY = scroller.getCurrY();
                            int dy = newY - mCurrentY;
                            mCurrentY = newY;
                            //进行平移操作
                            if (dx != 0 && dy != 0)
                                onTranslationImage(dx, dy);
                        }
                    }
                });
                translationAnimation.start();
                return super.onFling(e1, e2, velocityX, velocityY);
            }

            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                //单击事件
                if(onClickListener != null)
                    onClickListener.onClick(ZoomImageView.this);
                return true;
            }
        });

    }

    @Override
    public void setOnClickListener(OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }

    /**
     * imageView加载完成后调用,获取imageView加载完成后的图片大小
     */
    @Override
    public void onGlobalLayout() {
        if (mIsOneLoad) {

            //得到控件的宽和高
            int width = getWidth();
            int height = getHeight();

            //获取图片,如果没有图片则直接退出
            Drawable d = getDrawable();
            if (d == null)
                return;
            //获取图片的宽和高
            int dw = d.getIntrinsicWidth();
            int dh = d.getIntrinsicHeight();

            float scale = 1.0f;
            if (dw > width && dh <= height) {
                scale = width * 1.0f / dw;
            }
            if (dw <= width && dh > height) {
                scale = height * 1.0f / dh;
            }
            if ((dw <= width && dh <= height) || (dw >= width && dh >= height)) {
                scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
            }

            //图片原始比例,图片回复原始大小时使用
            mInitScale = scale;
            //图片双击后放大的比例
            mMidScale = mInitScale * 2;
            //手势放大时最大比例
            mMaxScale = mInitScale * 4;

            //设置移动数据,把改变比例后的图片移到中心点
            float translationX = width * 1.0f / 2 - dw / 2;
            float translationY = height * 1.0f / 2 - dh / 2;

            mScaleMatrix.postTranslate(translationX, translationY);
            mScaleMatrix.postScale(mInitScale, mInitScale, width * 1.0f / 2, height * 1.0f / 2);
            setImageMatrix(mScaleMatrix);
            mIsOneLoad = false;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return mScaleGestureDetector.onTouchEvent(event)|
                gestureDetector.onTouchEvent(event);
    }

    //手势操作(缩放)
    public void scale(ScaleGestureDetector detector) {

        Drawable drawable = getDrawable();
        if (drawable == null)
            return;

        float scale = getScale();
        //获取手势操作的值,scaleFactor>1说明放大,<1则说明缩小
        float scaleFactor = detector.getScaleFactor();
        //获取手势操作后的比例,当放操作后比例在[mInitScale,mMaxScale]区间时允许放大
        mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
        setImageMatrix(mScaleMatrix);
        removeBorderAndTranslationCenter();

    }

    //手势操作结束
    public void scaleEnd(ScaleGestureDetector detector) {
        float scale = getScale();
        scale = detector.getScaleFactor() * scale;
        if (scale < mInitScale) {
            scaleAnimation(mInitScale, getWidth() / 2, getHeight() / 2);
        } else if (scale > mMaxScale) {
            scaleAnimation(mMaxScale, getWidth() / 2, getHeight() / 2);
        }
    }

    //手势操作(移动)
    private void onTranslationImage(float dx, float dy) {

        if (getDrawable() == null)
            return;

        RectF rect = getMatrixRectF();

        //图片宽度小于控件宽度时不允许左右移动
        if (rect.width() <= getWidth())
            dx = 0.0f;

        //图片高度小于控件宽度时,不允许上下移动
        if (rect.height() <= getHeight())
            dy = 0.0f;

        //移动距离等于0,那就不需要移动了
        if (dx == 0.0f && dy == 0.0f)
            return;

        //是一个矩阵操作,用于在当前的缩放矩阵基础上进行平移操作。它将图像沿着 x 和 y 轴分别平移 dx 和 dy 的距离。
        //在给定的代码中,mScaleMatrix 是一个用于缩放和平移图像的矩阵对象。通过调用 postTranslate(dx, dy) 方法,将图像沿着 x 和 y 轴平移指定的距离。
        //这个平移操作会影响到 setImageMatrix(mScaleMatrix),将更新后的矩阵应用到图像视图上,从而实现图像的平移效果。
        //总结起来,mScaleMatrix.postTranslate(dx, dy) 的作用是在当前的缩放矩阵基础上对图像进行平移操作,使图像在屏幕上移动指定的距离。
        mScaleMatrix.postTranslate(dx, dy);
        setImageMatrix(mScaleMatrix);
        //去除移动边界
        removeBorderAndTranslationCenter();
    }

    //消除控件边界和把图片移动到中间
    private void removeBorderAndTranslationCenter() {
        RectF rectF = getMatrixRectF();
        if (rectF == null)
            return;

        int width = getWidth();
        int height = getHeight();
        float widthF = rectF.width();
        float heightF = rectF.height();
        float left = rectF.left;
        float right = rectF.right;
        float top = rectF.top;
        float bottom = rectF.bottom;
        float translationX = 0.0f, translationY = 0.0f;

        if (left > 0) {
            //左边有边界
            if (widthF > width) {
                //图片宽度大于控件宽度,移动到左边贴边
                translationX = -left;
            } else {
                //图片宽度小于控件宽度,移动到中间
                translationX = width * 1.0f / 2f - (widthF * 1.0f / 2f + left);
            }
        } else if (right < width) {
            //右边有边界
            if (widthF > width) {
                //图片宽度大于控件宽度,移动到右边贴边
                translationX = width - right;
            } else {
                //图片宽度小于控件宽度,移动到中间
                translationX = width * 1.0f / 2f - (widthF * 1.0f / 2f + left);
            }
        }

        if (top > 0) {
            //顶部有边界
            if (heightF > height) {
                //图片高度大于控件高度,去除顶部边界
                translationY = -top;
            } else {
                //图片高度小于控件宽度,移动到中间
                translationY = height * 1.0f / 2f - (top + heightF * 1.0f / 2f);
            }
        } else if (bottom < height) {
            //底部有边界
            if (heightF > height) {
                //图片高度大于控件高度,去除顶部边界
                translationY = height - bottom;
            } else {
                //图片高度小于控件宽度,移动到中间
                translationY = height * 1.0f / 2f - (top + heightF * 1.0f / 2f);
            }
        }

        mScaleMatrix.postTranslate(translationX, translationY);
        setImageMatrix(mScaleMatrix);
    }

    /**
     * 双击改变大小
     *
     * @param x 点击的中心点
     * @param y 点击的中心点
     */
    private void onDoubleDrowScale(float x, float y) {
        //如果缩放动画已经在执行,那就不执行任何事件
        if (mAnimator != null && mAnimator.isRunning())
            return;

        float drowScale = getDoubleDrowScale();
        //执行动画缩放,不然太难看了
        scaleAnimation(drowScale, x, y);
    }

    /**
     * 缩放动画
     *
     * @param drowScale 缩放的比例
     * @param x         中心点
     * @param y         中心点
     */
    private void scaleAnimation(final float drowScale, final float x, final float y) {
        if (mAnimator != null && mAnimator.isRunning())
            return;
        mAnimator = ObjectAnimator.ofFloat(getScale(), drowScale);
        mAnimator.setDuration(500);
        mAnimator.setInterpolator(new AccelerateInterpolator());
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = ((float) animation.getAnimatedValue()) / getScale();
                mScaleMatrix.postScale(value, value, x, y);
                setImageMatrix(mScaleMatrix);
                removeBorderAndTranslationCenter();
            }
        });

        mAnimator.start();
    }


    //返回双击后改变的大小比例(我们希望缩放误差在deviation范围内)
    private float getDoubleDrowScale() {
        float deviation = 0.05f;
        float drowScale = 1.0f;
        float scale = getScale();

        if (Math.abs(mInitScale - scale) < deviation)
            scale = mInitScale;
        if (Math.abs(mMidScale - scale) < deviation)
            scale = mMidScale;
        if (Math.abs(mMaxScale - scale) < deviation)
            scale = mMaxScale;

        if (scale != mMidScale) {
            //当前大小不等于mMidScale,则调整到mMidScale
            drowScale = mMidScale;
            isEnlarge = scale < mMidScale;
        } else {
            //如果等于mMidScale,则判断放大或者缩小
            //判断是放大或者缩小,如果上次是放大,则继续放大,缩小则继续缩小
            if (isEnlarge) {
                //放大
                drowScale = mMaxScale;
            } else {
                //缩小
                drowScale = mInitScale;
            }
        }
        return drowScale;
    }


    //获取图片宽高以及左右上下边界
    private RectF getMatrixRectF() {

        Drawable drawable = getDrawable();
        if (drawable == null) {
            return null;
        }
        RectF rectF = new RectF(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
        Matrix matrix = getImageMatrix();
        matrix.mapRect(rectF);

        return rectF;
    }


    /**
     * 获取当前图片的缩放值
     *
     * @return
     */
    private float getScale() {
        float[] values = new float[9];
        mScaleMatrix.getValues(values);
        return values[Matrix.MSCALE_X];
    }


    /**
     * 解决和父控件滑动冲突 只要图片边界超过控件边界,返回true
     *
     * @param direction
     * @return true 禁止父控件滑动
     */
    @Override
    public boolean canScrollHorizontally(int direction) {
        RectF rect = getMatrixRectF();
        if (rect == null || rect.isEmpty())
            return false;

        if (direction > 0) {
            return rect.right >= getWidth() + 1;
        } else {
            return rect.left <= 0 - 1;
        }

    }

    /**
     *
     *
     * @param direction
     * @return
     */
    @Override
    public boolean canScrollVertically(int direction) {
        RectF rect = getMatrixRectF();
        if (rect == null || rect.isEmpty())
            return false;

        if (direction > 0) {
            return rect.bottom >= getHeight() + 1;
        } else {
            return rect.top <= -1;
        }
    }


}

        然后就是写viewpager的适配器,我参考的是原作者的代码,然后我自己改进了一下,因为作者的代码是10年前的了,原作者代码参考链接https://github.com/tenthbitinc/ZoomImageView,他用的还是以前的线程在加载图片,我自己用glide加载图片,代码如下:

import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;

import java.util.List;

public class ImageAdapter extends PagerAdapter {
    /**
     * 传递过来的数据
     */
    private final List<WallPaperResponse.ResBean.VerticalBean> verticalBean;

    public ImageAdapter(List<WallPaperResponse.ResBean.VerticalBean> verticalBean) {
        this.verticalBean=verticalBean;
    }

    @Override
    public int getCount() {
        return verticalBean.size();
    }

    @Override
    public View instantiateItem(ViewGroup container, int position) {
        final ZoomImageView zoomImageView = new ZoomImageView(container.getContext());

        final String bitmapResource = verticalBean.get(position).getImg();

        //.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)来启用Glide的默认磁盘缓存策略。这样可以确保在需要时从缓存加载位图,并在不再需要时自动释放资源。
        Glide.with(zoomImageView)
                .asBitmap()
                .load(bitmapResource)
                .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
                .into(zoomImageView);

        container.addView(zoomImageView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

        return zoomImageView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }

}

        我自己用的是一MVVM的架构,设置好viewpager适配器就行,代码如下:

public class PictureViewActivity extends AppCompatActivity{

    private ViewPager viewPager;
    private PictureViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_picture_view);
        viewModel = new ViewModelProvider(this).get(PictureViewModel.class);
        int img = getIntent().getIntExtra("img",0);
        initView();
        //热门壁纸 网络请求
        viewModel.getWallPaper();
        viewModel.wallPaper.observe(this,wallPapers -> {
            viewPager.setAdapter(new ImageAdapter(wallPapers));
            viewPager.setCurrentItem(img,false);
        });
    }

    /**
     * 初始化
     */
    private void initView() {
        viewPager=findViewById(R.id.vp);
        //在页面之间添加边距(可选)
        viewPager.setPageMargin((int) getResources().getDisplayMetrics().density * 10);
    }

}

Android 实现单指滑动、双指缩放照片 Android实现放大缩小 阅读详情

相关推荐

Android ZoomImageView:图片缩放和平移实现指南

本文还有配套的精品资源,点击获取 简介:在Android开发中,实现图片的缩放和平移功能通常需要扩展ImageView类。本文深入探讨ZoomImageView的实现原理,包括缩放和平移的核心功能,以及如何通过监听触摸事件和计算Matrix矩阵来处理这些功能。文章提供了ZoomImageView的基础框架代码,并解释了其工作原理,旨在帮助开发者更好地理解Android图像处...

weixin_30978239的博客 1432

Android多点触控放大缩小双击之ZoomImageView自定义View使用

ZoomImageView简单使用方法

weixin_45920642的博客 863

Android大图预览与缩放控件ZoomImageView实战指南

自定义触摸事件的拦截和处理可以允许我们实现更复杂的用户交互逻辑。通过重写和方法,开发者可以控制事件的拦截和消费。当需要对触摸事件进行自定义处理时,首先考虑方法,它可以阻止事件继续向子视图传递。例如,一个滑动菜单可能需要在开始滑动时拦截事件,防止内容视图接收到事件而滚动。在中,可以通过处理触摸事件来响应用户的动作,如滑动、点击等。通常,这些逻辑会根据事件类型来判断并执行相应的操作。@Override// 处理点击事件。

weixin_35749545的博客 1198

探究ZoomImageVie中的图片居中和多点触控

  ZoomImageView是一个支持收拾缩放,多点触控的开源控件,这篇文章学习他的图片居中和手势缩放。要缩放的是一个图片所以要用到自定义控件,我们MyZoomImageView,继承自AppCompatImageView实现他的构造方法,既然是图片的处理,我们这里用到了一个类Matrix,他是一个3×3的一个矩阵,可以对图片进行缩放、旋转、位移、倾斜等处理。因此需要在构造方法里面进行初始化,...

一杯清泉 663

zoomImageView:图片浏览,多点触控、双击缩放

zoomImageView 图片浏览,多点触控、双击缩放

ZoomImageView

根据PhotoView优化,支持双指、双击缩放。在onTouch事件中模仿onClick事件,在放大时候拖动会有小bug,单文件集成加单,可直接代替ImageView使用

android 下拉背景放大,GitHub - old-traveler/HeadZoomLayout: 一个可以下拉放大头部背景图的布局控件...

HeadZoomLayout一个可以下拉放大头部背景图的布局控件,可轻松实现下拉放大头部背景图和QQ个人信息页面下拉扩展并放大背景图效果非入侵式,不干扰业务代码、不影响子View的滑动。类似于官方的SwipeRefreshLayout1.0.5之后迁移androidx可包裹以下控件使用RecyclerViewListViewScrollViewNestedScrollViewLinearLay...

weixin_36394468的博客 383

ZoomImageView:自定义ImageView控件,以实现对相册图片的手势缩放、双击缩放,放大后平移查看

ZoomImageView 自定义ImageView控件,以实现对相册图片的手势缩放、双击缩放,放大后平移查看 技术要点: 1.自由的使用手势,用两根手指缩放动作产生的放大与缩小 2.双击图片后产生的放大与缩小 3.放大以后,可以对图片进行自由的移动查看细节 4.处理与ViewPager之间的拦截事件冲突 ------------------------------------ 需要用到的知识点 1.Matrix 图片的缩放是通过矩阵变换来实现的,原理是: xScale xSkew xTrans ySkew yScale yTrans 0 0 0 它的数据结构是一个一维数组,程序中用全局变量mScaleMatrix来保存。 mScaleMatrix会调用postScale()、postTranslate()等方法来设置矩阵变换。 最后再用se

Android实现图片点击放大

Android实现图片点击放大,图片预览

stay_beam的博客 2929

Android实现图片手势缩放、移动、双击放大缩小

Android实现图片手势缩放、移动、双击放大缩小。

CDR学习笔记——02

这篇写一些高级CDR的架构原理。

... 1006

Android多点触控技术实战,自由地对图片进行缩放和移动

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11100327 在上一篇文章中我带着大家一起实现了Android瀑布流照片墙的效果,虽然这种效果很炫很酷,但其实还只能算是一个半成品,因为照片墙中所有的图片都是只能看不能点的。因此本篇文章中,我们就来对这一功能进行完善,加入点击图片就能浏览大图的功能,并且在浏览大图的时候还可以通过...

923723914 405

Vue3 - 手机移动端H5网页强力解决弹起软键盘后页面被挤压变形或页面整体上移问题,点击input输入框键盘弹出底部被上推往上顶遮挡及各种问题(兼容安卓苹果ios手机,微信公众号网页微信内置浏览器)

vue3,h5网页,input输入框组件,vue3 h5软键盘弹出,vue3输入框,键盘弹起时页面整体上移问题,uni,H5页面,解决软键盘弹起页面被挤压、被往顶的问题,解决vue3输入框,键盘弹起时页面整体上移问题,vue3调用手机系统软键盘,页面窗口被顶起,布局定位失效,解决VUE3软键盘弹起导致页面fixed定位元素被顶上去,输入法软键盘弹起,窗口顶起,变形解决办法,Vue中input组件在IOS设备上弹出软键盘时页面整体上移问题的解决方案,以及input组件聚焦后弹出软键盘固定在,Vue3软键盘把界

🏆 前端领域优质创作者 1万+

Android点击放大图片

属性onClick、放大动画

weixin_44251262的博客 971

ArcGIS笔记2_如何将经纬度WGS84地理坐标系转换为米单位CGCS2000投影坐标系

本博文则主要讲解,如果我们手里拿到的shp文件是在ArcGIS中,如何将经纬度WGS84地理坐标系转换为米单位CGCS2000投影坐标系。

晏长街的博客 4万+

MOSFET雪崩特性参数解析

但是,一些电源在输出短路时,初级中会产生较大的电流,加上初级电感,器件就会有雪崩损坏的可能,因此在这样的应用条件下,就要考虑器件的雪崩能量。对于那些在MOSFET的D和S极产生较大电压的尖峰应用,就要考虑器件的雪崩能量,电压的尖峰所集中的能量主要由电感和电流所决定,因此对于反激的应用,MOSFET关断时会产生较大的电压尖峰。雪崩击穿能量标定了器件可以容忍的瞬时过冲电压的安全值,其依赖于雪崩击穿需要消散的能量。EAS单脉冲雪崩击穿能量, EAS标定了器件可以安全吸收反向雪崩击穿能量的高低。

Airer_00的博客 799

android ImageView 手势缩放,双击放大,自由滑动,多点触控,惯性滑动

兼容viewPager import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Matrix; import android.graphics.RectF; import and...

jingzz1的博客 4455

ardupilot 方向余弦矩阵/旋转矩阵的理解

本节主要记录自己对ardupilot中用到的方向余弦矩阵/旋转矩阵的理解,欢迎批评指正,有些资料参考网上写的比较好的资料,免得查找资料麻烦。旋转矩阵的坐标理解:表示从旋转矩阵的下标的坐标系的坐标变换到上标表示的坐标系坐标下。旋转矩阵的坐标系理解:表示从旋转矩阵的上标的坐标系变换到下标表示的坐标系下。从旋转矩阵的投影更好理解,比如下面旋转矩阵的第一行是左边坐标系的第一维分量在右边坐标系的投影。

陌城烟雨 609

android view 实现双指平移、缩放、旋转

ZoomView 是一个可以实现单指平移,双指缩放和旋转的view,内部包含的view也会跟着一起变化,示例继承自RelativeLayout,也可以根据自己需要继承自所有View类的子类。 核心逻辑代码如下所示,需要的同学直接copy下面的代码到工程中就可以直接使用: import android.content.Context; import android.util.AttributeSet...

百分百空手接白刃 4378

银行监管报送系统系列介绍(二十一):银行监管报送系统总览

为保护法院案件当事人、利害关系人的合法权益,全面落实《最高人民法院、中国银行业监督管理委员会关于人民法院与银行业金融机构开展网络执行查控和联合信用惩戒工作的意见》(法【2014】266号),最高人民法院和银监会联合下发了《人民法院、银行业金融机构网络执行查控工作规范》(法【2015】321号),要求银行金融机构配合最高人民法院开展 “总对总”网络执行查控工作,并建立相应的业务系统,实现与法院的网络对接,协助法院完成对被执行人银行账户存款及其他金融资金的网络查询、冻结与扣划工作。

银行信息系统应用架构详解 2846

TC3XX - MCAL知识点(三十三):基于EB Tresos配置Tc3xx的MCAL代码如何产生中心对称的三相六路发波波形

本文用于记录如何在英飞凌 tc3xx 芯片的应用开发中,借助 EB Tresos 配置工具生成的配置代码与 MCAL 源码相结合,进而实现三相六路中心对称互补的 PWM 输出效果。外部资源需求:EB Tresos23.0以上、Tasking\Hightec编译器、示波器\逻辑分析仪。

梦想技术家 1186

android自定义放大缩小按钮,Android------实现图片双击放大,缩小,左右滑动的多种方式...

项目中常常有图片浏览功能。像微信朋友圈图片浏览,QQ空间照片浏览 的功能。实现图片双击放大,缩小,左右滑动等效果。来看看我的效果图,希望能满足你的要求 前三个button按钮是参考网上的多种实现方式,三种自定义图片控件,第4个是ViewPager实现图片左右滑动public class ViewPagerImageViewZQUI extends AppCompatActivity {Vie...

weixin_39743824的博客 493

Python爬虫实战:利用Playwright+Asyncio高效获取淘宝商品价格变化曲线

本文将详细介绍如何使用Python最新技术栈(Playwright+Asyncio)构建一个高效的淘宝商品价格监控爬虫系统。我们将从爬虫基础知识讲起,逐步深入到反爬应对策略、数据存储与分析,最终实现价格变化曲线的可视化展示。文章包含完整的代码实现和详细的技术解析,适合中高级Python开发者学习参考。关键词:Python爬虫、Playwright、Asyncio、淘宝价格监控、数据可视化支持多浏览器(Chromium, Firefox, WebKit)更快的执行速度更丰富的API。

2201_76125261的博客 241

使用Android Studio 切换图片

创作原因: 由于今天老师要求我们使用Android Studio制作电子相册,但我个人还不太会了解具体的详细步骤,所以根据先前所学知识,写了个利用Android Studio 切换图片,新手上路,请多指教。 一、思维导图: 二、项目 1.创建项目 2. 挑选自己喜欢的照片,放到mipmap文件里。 完善xml代码 4.完善activity方法里的代码 package com.exampl...

Feifei 8420

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Android studio App开发 图像切换器 在同一个组件中切换不同照片

图像切换器 实现通过点击上一张下一张切换图片的功能。 通过实现ImageSwitcher来实现。 会用到的方法: ImageSwitcher, ViewSwitcher.ViewFactory, makeView() , setImageResource()。 实现步骤 步骤一: 修改布局管理器 需要添加两个Button和一个ImageSwitcher。 代码如下: <LinearLayo...

Ace_bb的博客 2529

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Android AOP 的统一闸门与代价:Around 阻断、编译耗时与堆栈错乱

切面虽能集中横切逻辑,却打断了代码的因果链,导致问题难以追踪。本文通过语音关机误触发、空指针、点击无响应等案例,揭示切面滥用风险:proceed() 成唯一放行口,执行路径隐匿于字节码。提出“闸门”思想——在关键操作前加前置校验,分三种写法:完全替换、条件放行、参数清洗,强调proceed()仅一次放行,重试应由业务层处理。结合登录态、点击防抖等真实场景,说明注解+切面可实现声明式控制,但需注意作用域、生命周期与织入策略,避免全局变量干扰与内存泄漏。

mmsx990的博客 503

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

上一篇: Spring 集成 MobileIMSDK
下一篇: 安卓ShimmerFrameLayout XML app参数说明
qq_921124136
博客等级 码龄8年 74粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值