功能简介
- URL图片列表左右滑动,缩放预览。
- 图片预加载,浏览当前,预加载下一张,否则不加载。
效果展示
代码实现
package com.example.framedemo.view.view0004;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import com.example.framedemo.view.viewParent.BaseView;
import java.util.ArrayList;
import java.util.List;
/**
* 图片浏览专用View
* @Author 绝命三郎
*/
public class PictureBrowseView extends BaseView {
public PictureBrowseView(Context context) {
this(context,null);
}
public PictureBrowseView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
private View view;
private List<Bitmap> bitmapList =new ArrayList<>();
public PictureBrowseView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private float widthSize;
private float heightSize;
private Paint bitmapPaint;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
widthSize=MeasureSpec.getSize(widthMeasureSpec);
heightSize=MeasureSpec.getSize(heightMeasureSpec);
bitmapPaint=new Paint();
bitmapPaint.setStrokeWidth(0);
zoomPointX=widthSize/2f;
zoomPointY=heightSize/2f;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int k=0;k<bitmapList.size();k++){
Bitmap thisBitmap=bitmapList.get(k);
float bitmapWidth=thisBitmap.getWidth();
float bitmapHeight=thisBitmap.getHeight();
float step=widthSize/bitmapWidth;
//裁剪图片中的部分(此处:全图)
Rect rect=new Rect(0, 0,(int)bitmapWidth,(int)bitmapHeight);
float left=0+(k*widthSize)+moveValue;
float top=(heightSize/2f)-((bitmapHeight*step)/2f);
float right=widthSize+(k*widthSize)+moveValue;
float bottom=(heightSize/2f)+((bitmapHeight*step)/2f);
float proportionalValue=bitmapHeight/bitmapWidth;//图片宽高比例值
if (k==-sourceIndex){//缩放当前图片
float widthZoomValue= (float) thisZoomValue;
float heightZoomValue=widthZoomValue*proportionalValue;
//显示在屏幕什么位置
RectF rectF=new RectF(
(float) (left-widthZoomValue),
(float) (top-heightZoomValue),
(float) (right+widthZoomValue),
(float) (bottom+heightZoomValue));
canvas.drawBitmap(thisBitmap,rect,rectF,bitmapPaint);
}else {//其余图片不用缩放
//显示在屏幕什么位置
RectF rectF=new RectF((float) left, (float) top, (float) right, (float) bottom);
canvas.drawBitmap(thisBitmap,rect,rectF,bitmapPaint);
}
}
}
private float downX;
float moveValue=0;//所有的滑动值累加
float oldMoveValue=0;
private int sourceIndex=0;//资源索引值
private double nLenStart;
private double nLenEnd;
private boolean zoomActionTag=false;//缩放事件标签:事件锁定为缩放事件时为true, 非缩放为false
private float zoomPointX;//缩放点X
private float zoomPointY;//缩放点Y
@Override
public boolean onTouchEvent(MotionEvent event) {
int pCount = event.getPointerCount();// 触摸设备时手指的数量
int action = event.getAction();// 获取触屏动作。比如:按下、移动和抬起等手势动作
boolean isZoomTouch=(action & MotionEvent.ACTION_MASK)== MotionEvent.ACTION_POINTER_DOWN && pCount == 2;
boolean isZoomTouchMove=(action & MotionEvent.ACTION_MASK)== MotionEvent.ACTION_MOVE && pCount == 2;
// 手势按下且屏幕上是两个手指数量时
if (isZoomTouch){
//锁定为缩放事件
zoomActionTag=true;
zoomPointX=event.getX();
zoomPointY=event.getY();
// 获取按下时候两个坐标的x轴的水平距离,取绝对值
int xLen = Math.abs((int)event.getX(0) - (int)event.getX(1));
// 获取按下时候两个坐标的y轴的水平距离,取绝对值
int yLen = Math.abs((int)event.getY(0) - (int)event.getY(1));
// 根据x轴和y轴的水平距离,求平方和后再开方获取两个点之间的直线距离。此时就获取到了两个手指刚按下时的直线距离
nLenStart = Math.sqrt((double) xLen * xLen + (double) yLen * yLen);
}else if (isZoomTouchMove){// 手势滑动或抬起且屏幕上是两个手指数量时
// 获取抬起时候两个坐标的x轴的水平距离,取绝对值
int xLen = Math.abs((int)event.getX(0) - (int)event.getX(1));
// 获取抬起时候两个坐标的y轴的水平距离,取绝对值
int yLen = Math.abs((int)event.getY(0) - (int)event.getY(1));
// 根据x轴和y轴的水平距离,求平方和后再开方获取两个点之间的直线距离。此时就获取到了两个手指抬起时的直线距离
nLenEnd = Math.sqrt((double) xLen * xLen + (double) yLen * yLen);
// 根据手势按下时两个手指触点之间的直线距离A和手势抬起时两个手指触点之间的直线距离B。比较A和B的大小,得出用户是手势放大还是手势缩小
if(nLenEnd > nLenStart){
//Toast.makeText(this, "手势放大", Toast.LENGTH_SHORT).show();
Log.d("fxHou","手势滑动放大");
zoomMethod(nLenEnd-nLenStart);
return true;
}else if(nLenEnd < nLenStart){
//Toast.makeText(this, "手势缩小", Toast.LENGTH_SHORT).show();
Log.d("fxHou","手势滑动缩小");
zoomMethod(nLenEnd-nLenStart);
return true;
}
}
//释放缩放事件
if (event.getAction()==MotionEvent.ACTION_UP && zoomActionTag){
zoomActionTag=false;
this.thisZoomValue =0;
postInvalidate();
return true;
}
//往下是处理左右滑动和单击
if (!zoomActionTag){
if (event.getAction()==MotionEvent.ACTION_DOWN){
Log.d("fxHou","按下");
downX=event.getX();
oldMoveValue=moveValue;
return true;
}
if (event.getAction()==MotionEvent.ACTION_MOVE){
moveValue=oldMoveValue+(event.getX()-downX);
postInvalidate();
Log.d("fxHou","滑动");
}
if (event.getAction()==MotionEvent.ACTION_UP){
Log.d("fxHou","抬起 sourceIndex="+sourceIndex);
if ((event.getX()-downX)>100){
//手指向右滑:
if (sourceIndex!=0)sourceIndex=sourceIndex+1;
moveValue=widthSize*(sourceIndex);
postInvalidate();
}else if ((event.getX()-downX)<-100){
//手指向左滑:
postInvalidate();
if (sourceIndex!=-(bitmapList.size()-1))sourceIndex=sourceIndex-1;
moveValue=widthSize*(sourceIndex);
}else {
//单击事件:
Log.d("fxHou","单击");
}
return true;
}
}
return super.onTouchEvent(event);
}
//缩放大事件(缩放大值)
private double thisZoomValue=0;
private void zoomMethod(double thisZoomValue) {
this.thisZoomValue =thisZoomValue;
postInvalidate();
}
//通过Url转换为Bitmap
public void setUrl(List<String> urlList) {
new Thread(new Runnable() {
@Override
public void run() {
for (String url: urlList){
urlToBitmap(url);
}
}
}).start();
}
//直接给Bitmap
public void setBitmap(List<Bitmap> bitmapList) {
this.bitmapList=bitmapList;
}
private void urlToBitmap(String url){
//使用Glide框架将URL转为Bitmap(Glide自带缓存) 注: 请自行引入Glide依赖,此处不做讲解
try {
Bitmap bitmap = Glide.with(getContext())
.asBitmap()
.load(url)
.submit(900, 1200).get();
if (bitmap!=null) {
if (!bitmapList.contains(bitmap))bitmapList.add(bitmap);
Log.d("fxHou","Bitmap Size="+bitmapList.size());
BaseCacheFactory.getInstance().putBitMap(url,bitmap);//缓存bitmap
}
postInvalidate();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
使用方法
- 在XML中使用VIEW
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#323232"
tools:context=".controller.activity.MainActivity">
<com.example.framedemo.view.view0004.PictureBrowseView
android:id="@+id/pictureView"
android:background="@color/black"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- 导入数据
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<String> urlList =new ArrayList<>();
urlList.add("http://www.juemingsanlang.com/source/Public/OfficialPicture/202208142210061006.jpg");
urlList.add("http://www.juemingsanlang.com/source/Public/OfficialPicture/202208142211011008.jpg");
urlList.add("http://www.juemingsanlang.com/source/Public/OfficialPicture/202208142212241010.jpg");
urlList.add("http://www.juemingsanlang.com/source/Public/OfficialPicture/202209011116431012.jpg");
urlList.add("http://www.juemingsanlang.com/source/Public/OfficialPicture/202209011425001016.jpg");
urlList.add("http://www.juemingsanlang.com/source/Public/OfficialPicture/202209011721231020.jpg");
PictureBrowseView pictureView=(PictureBrowseView) findViewById(R.id.pictureView);
pictureView.setUrl(urlList);
}
}
完成!