This commit is contained in:
jinyuer
2020-08-11 14:48:10 +08:00
parent 1686ba94e9
commit fa1413fc30
57 changed files with 3142 additions and 122 deletions

1
ninegridview/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

30
ninegridview/build.gradle Normal file
View File

@@ -0,0 +1,30 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
buildToolsVersion "27.0.3"
defaultConfig {
minSdkVersion 21
targetSdkVersion 27
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:27.1.1'
compile 'com.android.support:support-annotations:27.1.1'
compile 'com.github.chrisbanes.photoview:library:1.2.4'
implementation files('../app/libs/pldroid-player-2.1.9.jar')
}
//apply from: '../bintray.gradle'

17
ninegridview/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\Android\SDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@@ -0,0 +1,16 @@
<manifest
package="com.lzy.ninegrid"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application>
<activity
android:name="com.lzy.ninegrid.preview.ImagePreviewActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
<activity android:name=".preview.VideoPreviewActivity" android:theme="@android:style/Theme.Black.NoTitleBar"/>
</application>
</manifest>

View File

@@ -0,0 +1,91 @@
package com.lzy.ninegrid;
import java.io.Serializable;
/**
* ================================================
* 作 者:廖子尧
* 版 本1.0
* 创建日期2016/3/21
* 描 述:
* 修订历史:
* ================================================
*/
public class ImageInfo implements Serializable {
public String thumbnailUrl;
public String bigImageUrl;
public int imageViewHeight;
public int imageViewWidth;
public int imageViewX;
public int imageViewY;
public int type;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
public String getBigImageUrl() {
return bigImageUrl;
}
public void setBigImageUrl(String bigImageUrl) {
this.bigImageUrl = bigImageUrl;
}
public int getImageViewHeight() {
return imageViewHeight;
}
public void setImageViewHeight(int imageViewHeight) {
this.imageViewHeight = imageViewHeight;
}
public int getImageViewWidth() {
return imageViewWidth;
}
public void setImageViewWidth(int imageViewWidth) {
this.imageViewWidth = imageViewWidth;
}
public int getImageViewX() {
return imageViewX;
}
public void setImageViewX(int imageViewX) {
this.imageViewX = imageViewX;
}
public int getImageViewY() {
return imageViewY;
}
public void setImageViewY(int imageViewY) {
this.imageViewY = imageViewY;
}
@Override
public String toString() {
return "ImageInfo{" +
"thumbnailUrl='" + thumbnailUrl + '\'' +
", bigImageUrl='" + bigImageUrl + '\'' +
", imageViewHeight=" + imageViewHeight +
", imageViewWidth=" + imageViewWidth +
", imageViewX=" + imageViewX +
", imageViewY=" + imageViewY +
", type=" + type +
'}';
}
}

View File

@@ -0,0 +1,43 @@
package com.lzy.ninegrid;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.pili.pldroid.player.widget.PLVideoView;
public class NineGridItemViewGroup extends FrameLayout {
private PLVideoView pv;
private ImageView iv;
public NineGridItemViewGroup(@NonNull Context context) {
super(context);
}
public NineGridItemViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.layout_item_ninegrid, this);
pv = findViewById(R.id.pv);
iv = findViewById(R.id.iv);
}
public void setVisibleVideo() {
iv.setVisibility(View.GONE);
pv.setVisibility(View.VISIBLE);
}
public void setImageVisible(ImageView.ScaleType type) {
pv.setVisibility(View.GONE);
iv.setVisibility(View.VISIBLE);
iv.setScaleType(type);
}
}

View File

@@ -0,0 +1,240 @@
package com.lzy.ninegrid;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.util.ArrayList;
import java.util.List;
public class NineGridView extends ViewGroup {
public static final int MODE_FILL = 0; //填充模式,类似于微信
public static final int MODE_GRID = 1; //网格模式类似于QQ4张图会 2X2布局
private static ImageLoader mImageLoader; //全局的图片加载器(必须设置,否者不显示图片)
private int singleImageSize = 250; // 单张图片时的最大大小,单位dp
private float singleImageRatio = 1.0f; // 单张图片的宽高比(宽/高)
private int maxImageSize = 9; // 最大显示的图片数
private int gridSpacing = 3; // 宫格间距单位dp
private int mode = MODE_FILL; // 默认使用fill模式
private int columnCount; // 列数
private int rowCount; // 行数
private int gridWidth; // 宫格宽度
private int gridHeight; // 宫格高度
private List<ImageView> imageViews;
private List<ImageInfo> mImageInfo;
private NineGridViewAdapter mAdapter;
public NineGridView(Context context) {
this(context, null);
}
public NineGridView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NineGridView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
DisplayMetrics dm = context.getResources().getDisplayMetrics();
gridSpacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gridSpacing, dm);
singleImageSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, singleImageSize, dm);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NineGridView);
gridSpacing = (int) a.getDimension(R.styleable.NineGridView_ngv_gridSpacing, gridSpacing);
singleImageSize = a.getDimensionPixelSize(R.styleable.NineGridView_ngv_singleImageSize, singleImageSize);
singleImageRatio = a.getFloat(R.styleable.NineGridView_ngv_singleImageRatio, singleImageRatio);
maxImageSize = a.getInt(R.styleable.NineGridView_ngv_maxSize, maxImageSize);
mode = a.getInt(R.styleable.NineGridView_ngv_mode, mode);
a.recycle();
imageViews = new ArrayList<>();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = 0;
int totalWidth = width - getPaddingLeft() - getPaddingRight();
if (mImageInfo != null && mImageInfo.size() > 0) {
if (mImageInfo.size() == 1) {
gridWidth = singleImageSize > totalWidth ? totalWidth : singleImageSize;
gridHeight = (int) (gridWidth / singleImageRatio);
//矫正图片显示区域大小,不允许超过最大显示范围
if (gridHeight > singleImageSize) {
float ratio = singleImageSize * 1.0f / gridHeight;
gridWidth = (int) (gridWidth * ratio);
gridHeight = singleImageSize;
}
} else {
// gridWidth = gridHeight = (totalWidth - gridSpacing * (columnCount - 1)) / columnCount;
//这里无论是几张图片,宽高都按总宽度的 1/3
gridWidth = gridHeight = (totalWidth - gridSpacing * 2) / 3;
}
width = gridWidth * columnCount + gridSpacing * (columnCount - 1) + getPaddingLeft() + getPaddingRight();
height = gridHeight * rowCount + gridSpacing * (rowCount - 1) + getPaddingTop() + getPaddingBottom();
}
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (mImageInfo == null) return;
int childrenCount = mImageInfo.size();
for (int i = 0; i < childrenCount; i++) {
ImageView childrenView = (ImageView) getChildAt(i);
int rowNum = i / columnCount;
int columnNum = i % columnCount;
int left = (gridWidth + gridSpacing) * columnNum + getPaddingLeft();
int top = (gridHeight + gridSpacing) * rowNum + getPaddingTop();
int right = left + gridWidth;
int bottom = top + gridHeight;
childrenView.layout(left, top, right, bottom);
if (mImageLoader != null) {
mImageLoader.onDisplayImage(getContext(), childrenView, mImageInfo.get(i).thumbnailUrl);
}
}
}
/** 设置适配器 */
public void setAdapter(@NonNull NineGridViewAdapter adapter) {
mAdapter = adapter;
List<ImageInfo> imageInfo = adapter.getImageInfo();
if (imageInfo == null || imageInfo.isEmpty()) {
setVisibility(GONE);
return;
} else {
setVisibility(VISIBLE);
}
int imageCount = imageInfo.size();
if (maxImageSize > 0 && imageCount > maxImageSize) {
imageInfo = imageInfo.subList(0, maxImageSize);
imageCount = imageInfo.size(); //再次获取图片数量
}
//默认是3列显示行数根据图片的数量决定
rowCount = imageCount / 3 + (imageCount % 3 == 0 ? 0 : 1);
columnCount = 3;
//grid模式下显示4张使用2X2模式
if (mode == MODE_GRID) {
if (imageCount == 4) {
rowCount = 2;
columnCount = 2;
}
}
//保证View的复用避免重复创建
if (mImageInfo == null) {
for (int i = 0; i < imageCount; i++) {
ImageView iv = getImageView(i);
if (iv == null) return;
addView(iv, generateDefaultLayoutParams());
}
} else {
int oldViewCount = mImageInfo.size();
int newViewCount = imageCount;
if (oldViewCount > newViewCount) {
removeViews(newViewCount, oldViewCount - newViewCount);
} else if (oldViewCount < newViewCount) {
for (int i = oldViewCount; i < newViewCount; i++) {
ImageView iv = getImageView(i);
if (iv == null) return;
addView(iv, generateDefaultLayoutParams());
}
}
}
//修改最后一个条目,决定是否显示更多
if (adapter.getImageInfo().size() > maxImageSize) {
View child = getChildAt(maxImageSize - 1);
if (child instanceof NineGridViewWrapper) {
NineGridViewWrapper imageView = (NineGridViewWrapper) child;
imageView.setMoreNum(adapter.getImageInfo().size() - maxImageSize);
}
}
mImageInfo = imageInfo;
requestLayout();
}
/** 获得 ImageView 保证了 ImageView 的重用 */
private ImageView getImageView(final int position) {
ImageView imageView;
if (position < imageViews.size()) {
imageView = imageViews.get(position);
} else {
imageView = mAdapter.generateImageView(getContext());
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mAdapter.onImageItemClick(getContext(), NineGridView.this, position, mAdapter.getImageInfo());
}
});
imageViews.add(imageView);
}
return imageView;
}
/** 设置宫格间距 */
public void setGridSpacing(int spacing) {
gridSpacing = spacing;
}
/** 设置只有一张图片时的宽 */
public void setSingleImageSize(int maxImageSize) {
singleImageSize = maxImageSize;
}
/** 设置只有一张图片时的宽高比 */
public void setSingleImageRatio(float ratio) {
singleImageRatio = ratio;
}
/** 设置最大图片数 */
public void setMaxSize(int maxSize) {
maxImageSize = maxSize;
}
public int getMaxSize() {
return maxImageSize;
}
public static void setImageLoader(ImageLoader imageLoader) {
mImageLoader = imageLoader;
}
public static ImageLoader getImageLoader() {
return mImageLoader;
}
public interface ImageLoader {
/**
* 需要子类实现该方法,以确定如何加载和显示图片
*
* @param context 上下文
* @param imageView 需要展示图片的ImageView
* @param url 图片地址
*/
void onDisplayImage(Context context, ImageView imageView, String url);
/**
* @param url 图片的地址
* @return 当前框架的本地缓存图片
*/
Bitmap getCacheImage(String url);
}
}

View File

@@ -0,0 +1,51 @@
package com.lzy.ninegrid;
import android.content.Context;
import android.widget.ImageView;
import java.io.Serializable;
import java.util.List;
public abstract class NineGridViewAdapter implements Serializable {
protected Context context;
private List<ImageInfo> imageInfo;
public NineGridViewAdapter(Context context, List<ImageInfo> imageInfo) {
this.context = context;
this.imageInfo = imageInfo;
}
/**
* 如果要实现图片点击的逻辑,重写此方法即可
*
* @param context 上下文
* @param nineGridView 九宫格控件
* @param index 当前点击图片的的索引
* @param imageInfo 图片地址的数据集合
*/
protected void onImageItemClick(Context context, NineGridView nineGridView, int index, List<ImageInfo> imageInfo) {
}
/**
* 生成ImageView容器的方式默认使用NineGridImageViewWrapper类即点击图片后图片会有蒙板效果
* 如果需要自定义图片展示效果,重写此方法即可
*
* @param context 上下文
* @return 生成的 ImageView
*/
protected ImageView generateImageView(Context context) {
NineGridViewWrapper imageView = new NineGridViewWrapper(context);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageResource(R.drawable.ic_default_color);
return imageView;
}
public List<ImageInfo> getImageInfo() {
return imageInfo;
}
public void setImageInfoList(List<ImageInfo> imageInfo) {
this.imageInfo = imageInfo;
}
}

View File

@@ -0,0 +1,137 @@
package com.lzy.ninegrid;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.widget.ImageView;
public class NineGridViewWrapper extends ImageView {
private int moreNum = 0; //显示更多的数量
private int maskColor = 0x88000000; //默认的遮盖颜色
private float textSize = 35; //显示文字的大小单位sp
private int textColor = 0xFFFFFFFF; //显示文字的颜色
private TextPaint textPaint; //文字的画笔
private String msg = ""; //要绘制的文字
public NineGridViewWrapper(Context context) {
this(context, null);
}
public NineGridViewWrapper(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NineGridViewWrapper(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//转化单位
textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSize, getContext().getResources().getDisplayMetrics());
textPaint = new TextPaint();
textPaint.setTextAlign(Paint.Align.CENTER); //文字居中对齐
textPaint.setAntiAlias(true); //抗锯齿
textPaint.setTextSize(textSize); //设置文字大小
textPaint.setColor(textColor); //设置文字颜色
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (moreNum > 0) {
canvas.drawColor(maskColor);
float baseY = getHeight() / 2 - (textPaint.ascent() + textPaint.descent()) / 2;
canvas.drawText(msg, getWidth() / 2, baseY, textPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Drawable drawable = getDrawable();
if (drawable != null) {
/**
* 默认情况下所有的从同一资源R.drawable.XXX加载来的drawable实例都共享一个共用的状态
* 如果你更改一个实例的状态,其他所有的实例都会收到相同的通知。
* 使用使 mutate 可以让这个drawable变得状态不定。这个操作不能还原变为不定后就不能变为原来的状态
* 一个状态不定的drawable可以保证它不与其他任何一个drawabe共享它的状态。
* 此处应该是要使用的 mutate(),但是在部分手机上会出现点击后变白的现象,所以没有使用
* 目前这种解决方案没有问题
*/
// drawable.mutate().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
drawable.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
ViewCompat.postInvalidateOnAnimation(this);
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
Drawable drawableUp = getDrawable();
if (drawableUp != null) {
// drawableUp.mutate().clearColorFilter();
drawableUp.clearColorFilter();
ViewCompat.postInvalidateOnAnimation(this);
}
break;
}
return super.onTouchEvent(event);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
setImageDrawable(null);
}
public int getMoreNum() {
return moreNum;
}
public void setMoreNum(int moreNum) {
this.moreNum = moreNum;
msg = "+" + moreNum;
invalidate();
}
public int getMaskColor() {
return maskColor;
}
public void setMaskColor(int maskColor) {
this.maskColor = maskColor;
invalidate();
}
public float getTextSize() {
return textSize;
}
public void setTextSize(float textSize) {
this.textSize = textSize;
textPaint.setTextSize(textSize);
invalidate();
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
this.textColor = textColor;
textPaint.setColor(textColor);
invalidate();
}
}

View File

@@ -0,0 +1,38 @@
package com.lzy.ninegrid.preview;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
/** 修复图片在ViewPager控件中缩放报错的BUG */
public class HackyViewPager extends ViewPager {
public HackyViewPager(Context context) {
super(context);
}
public HackyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
}

View File

@@ -0,0 +1,238 @@
package com.lzy.ninegrid.preview;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.lzy.ninegrid.ImageInfo;
import com.lzy.ninegrid.R;
import java.util.List;
public class ImagePreviewActivity extends Activity implements ViewTreeObserver.OnPreDrawListener {
public static final String IMAGE_INFO = "IMAGE_INFO";
public static final String CURRENT_ITEM = "CURRENT_ITEM";
public static final int ANIMATE_DURATION = 200;
private RelativeLayout rootView;
private ImagePreviewAdapter imagePreviewAdapter;
private List<ImageInfo> imageInfo;
private int currentItem;
private int imageHeight;
private int imageWidth;
private int screenWidth;
private int screenHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preview2);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager2);
final TextView tv_pager = (TextView) findViewById(R.id.tv_pager);
rootView = (RelativeLayout) findViewById(R.id.rootView);
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
screenWidth = metric.widthPixels;
screenHeight = metric.heightPixels;
Intent intent = getIntent();
imageInfo = (List<ImageInfo>) intent.getSerializableExtra(IMAGE_INFO);
currentItem = intent.getIntExtra(CURRENT_ITEM, 0);
imagePreviewAdapter = new ImagePreviewAdapter(this, imageInfo);
viewPager.setAdapter(imagePreviewAdapter);
viewPager.setCurrentItem(currentItem);
viewPager.getViewTreeObserver().addOnPreDrawListener(this);
viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
currentItem = position;
tv_pager.setText(String.format(getString(R.string.select2), currentItem + 1, imageInfo.size()));
}
});
tv_pager.setText(String.format(getString(R.string.select2), currentItem + 1, imageInfo.size()));
}
@Override
public void onBackPressed() {
finishActivityAnim();
}
/** 绘制前开始动画 */
@Override
public boolean onPreDraw() {
rootView.getViewTreeObserver().removeOnPreDrawListener(this);
final View view = imagePreviewAdapter.getPrimaryItem();
final ImageView imageView = imagePreviewAdapter.getPrimaryImageView();
computeImageWidthAndHeight(imageView);
final ImageInfo imageData = imageInfo.get(currentItem);
final float vx = imageData.imageViewWidth * 1.0f / imageWidth;
final float vy = imageData.imageViewHeight * 1.0f / imageHeight;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.0f);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
long duration = animation.getDuration();
long playTime = animation.getCurrentPlayTime();
float fraction = duration > 0 ? (float) playTime / duration : 1f;
if (fraction > 1) fraction = 1;
view.setTranslationX(evaluateInt(fraction, imageData.imageViewX + imageData.imageViewWidth / 2 - imageView.getWidth() / 2, 0));
view.setTranslationY(evaluateInt(fraction, imageData.imageViewY + imageData.imageViewHeight / 2 - imageView.getHeight() / 2, 0));
view.setScaleX(evaluateFloat(fraction, vx, 1));
view.setScaleY(evaluateFloat(fraction, vy, 1));
view.setAlpha(fraction);
rootView.setBackgroundColor(evaluateArgb(fraction, Color.TRANSPARENT, Color.BLACK));
}
});
addIntoListener(valueAnimator);
valueAnimator.setDuration(ANIMATE_DURATION);
valueAnimator.start();
return true;
}
/** activity的退场动画 */
public void finishActivityAnim() {
final View view = imagePreviewAdapter.getPrimaryItem();
final ImageView imageView = imagePreviewAdapter.getPrimaryImageView();
computeImageWidthAndHeight(imageView);
final ImageInfo imageData = imageInfo.get(currentItem);
final float vx = imageData.imageViewWidth * 1.0f / imageWidth;
final float vy = imageData.imageViewHeight * 1.0f / imageHeight;
final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.0f);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
long duration = animation.getDuration();
long playTime = animation.getCurrentPlayTime();
float fraction = duration > 0 ? (float) playTime / duration : 1f;
if (fraction > 1) fraction = 1;
view.setTranslationX(evaluateInt(fraction, 0, imageData.imageViewX + imageData.imageViewWidth / 2 - imageView.getWidth() / 2));
view.setTranslationY(evaluateInt(fraction, 0, imageData.imageViewY + imageData.imageViewHeight / 2 - imageView.getHeight() / 2));
view.setScaleX(evaluateFloat(fraction, 1, vx));
view.setScaleY(evaluateFloat(fraction, 1, vy));
view.setAlpha(1 - fraction);
rootView.setBackgroundColor(evaluateArgb(fraction, Color.BLACK, Color.TRANSPARENT));
}
});
addOutListener(valueAnimator);
valueAnimator.setDuration(ANIMATE_DURATION);
valueAnimator.start();
}
/** 计算图片的宽高 */
private void computeImageWidthAndHeight(ImageView imageView) {
// 获取真实大小
try {
Drawable drawable = imageView.getDrawable();
int intrinsicHeight = drawable.getIntrinsicHeight();
int intrinsicWidth = drawable.getIntrinsicWidth();
// 计算出与屏幕的比例,用于比较以宽的比例为准还是高的比例为准,因为很多时候不是高度没充满,就是宽度没充满
float h = screenHeight * 1.0f / intrinsicHeight;
float w = screenWidth * 1.0f / intrinsicWidth;
if (h > w) h = w;
else w = h;
// 得出当宽高至少有一个充满的时候图片对应的宽高
imageHeight = (int) (intrinsicHeight * h);
imageWidth = (int) (intrinsicWidth * w);
}catch (Exception e){
}
}
/** 进场动画过程监听 */
private void addIntoListener(ValueAnimator valueAnimator) {
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
rootView.setBackgroundColor(0x0);
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
/** 退场动画过程监听 */
private void addOutListener(ValueAnimator valueAnimator) {
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
rootView.setBackgroundColor(0x0);
}
@Override
public void onAnimationEnd(Animator animation) {
finish();
overridePendingTransition(0, 0);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
/** Integer 估值器 */
public Integer evaluateInt(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int) (startInt + fraction * (endValue - startInt));
}
/** Float 估值器 */
public Float evaluateFloat(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
/** Argb 估值器 */
public int evaluateArgb(float fraction, int startValue, int endValue) {
int startA = (startValue >> 24) & 0xff;
int startR = (startValue >> 16) & 0xff;
int startG = (startValue >> 8) & 0xff;
int startB = startValue & 0xff;
int endA = (endValue >> 24) & 0xff;
int endR = (endValue >> 16) & 0xff;
int endG = (endValue >> 8) & 0xff;
int endB = endValue & 0xff;
return (startA + (int) (fraction * (endA - startA))) << 24//
| (startR + (int) (fraction * (endR - startR))) << 16//
| (startG + (int) (fraction * (endG - startG))) << 8//
| (startB + (int) (fraction * (endB - startB)));
}
}

View File

@@ -0,0 +1,128 @@
package com.lzy.ninegrid.preview;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import com.lzy.ninegrid.ImageInfo;
import com.lzy.ninegrid.NineGridView;
import com.lzy.ninegrid.R;
import java.util.List;
import uk.co.senab.photoview.PhotoView;
import uk.co.senab.photoview.PhotoViewAttacher;
/**
* ================================================
* 作 者:廖子尧
* 版 本1.0
* 创建日期2016/3/21
* 描 述:
* 修订历史:
* ================================================
*/
public class ImagePreviewAdapter extends PagerAdapter implements PhotoViewAttacher.OnPhotoTapListener {
private List<ImageInfo> imageInfo;
private Context context;
private View currentView;
public ImagePreviewAdapter(Context context, @NonNull List<ImageInfo> imageInfo) {
super();
this.imageInfo = imageInfo;
this.context = context;
}
@Override
public int getCount() {
return imageInfo.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
currentView = (View) object;
}
public View getPrimaryItem() {
return currentView;
}
public ImageView getPrimaryImageView() {
return (ImageView) currentView.findViewById(R.id.pv);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = LayoutInflater.from(context).inflate(R.layout.item_photoview, container, false);
final ProgressBar pb = (ProgressBar) view.findViewById(R.id.pb);
final PhotoView imageView = (PhotoView) view.findViewById(R.id.pv);
ImageInfo info = this.imageInfo.get(position);
imageView.setOnPhotoTapListener(this);
showExcessPic(info, imageView);
//如果需要加载的loading,需要自己改写,不能使用这个方法
NineGridView.getImageLoader().onDisplayImage(view.getContext(), imageView, info.bigImageUrl);
// pb.setVisibility(View.VISIBLE);
// Glide.with(context).load(info.bigImageUrl)//
// .placeholder(R.drawable.ic_default_image)//
// .error(R.drawable.ic_default_image)//
// .diskCacheStrategy(DiskCacheStrategy.ALL)//
// .listener(new RequestListener<String, GlideDrawable>() {
// @Override
// public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
// pb.setVisibility(View.GONE);
// return false;
// }
//
// @Override
// public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
// pb.setVisibility(View.GONE);
// return false;
// }
// }).into(imageView);
container.addView(view);
return view;
}
/** 展示过度图片 */
private void showExcessPic(ImageInfo imageInfo, PhotoView imageView) {
//先获取大图的缓存图片
Bitmap cacheImage = NineGridView.getImageLoader().getCacheImage(imageInfo.bigImageUrl);
//如果大图的缓存不存在,在获取小图的缓存
if (cacheImage == null) cacheImage = NineGridView.getImageLoader().getCacheImage(imageInfo.thumbnailUrl);
//如果没有任何缓存,使用默认图片,否者使用缓存
if (cacheImage == null) {
imageView.setImageResource(R.drawable.ic_default_color);
} else {
imageView.setImageBitmap(cacheImage);
}
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
/** 单击屏幕关闭 */
@Override
public void onPhotoTap(View view, float x, float y) {
((ImagePreviewActivity) context).finishActivityAnim();
}
}

View File

@@ -0,0 +1,601 @@
package com.lzy.ninegrid.preview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
import com.pili.pldroid.player.IMediaController;
import java.util.Locale;
/**
* You can write a custom MediaController instead of this class
* A MediaController widget must implement all the interface defined by com.pili.pldroid.player.IMediaController
*/
public class MediaController extends FrameLayout implements IMediaController {
private static final String TAG = "PLMediaController";
private IMediaController.MediaPlayerControl mPlayer;
private Context mContext;
private PopupWindow mWindow;
private int mAnimStyle;
private View mAnchor;
private View mRoot;
private ProgressBar mProgress;
private TextView mEndTime, mCurrentTime;
private long mDuration;
private boolean mShowing;
private boolean mDragging;
private boolean mInstantSeeking = true;
private long mSeekPosition = 0l;
private static int sDefaultTimeout = 3000;
private static final int SEEK_TO_POST_DELAY_MILLIS = 200;
private static final int FADE_OUT = 1;
private static final int SHOW_PROGRESS = 2;
private boolean mFromXml = false;
private ImageButton mPauseButton;
private ImageButton mFfwdButton;
private ImageButton mRewButton;
private ImageButton mNextButton;
private ImageButton mPrevButton;
private boolean mUseFastForward;
private static final int IC_MEDIA_PAUSE_ID = Resources.getSystem().getIdentifier("ic_media_pause", "drawable", "android");
private static final int IC_MEDIA_PLAY_ID = Resources.getSystem().getIdentifier("ic_media_play", "drawable", "android");
private static final int MEDIA_CONTROLLER_ID = Resources.getSystem().getIdentifier("media_controller", "layout", "android");
private static final int PRV_BUTTON_ID = Resources.getSystem().getIdentifier("prev", "id", "android");
private static final int FFWD_BUTTON_ID = Resources.getSystem().getIdentifier("ffwd", "id", "android");
private static final int NEXT_BUTTON_ID = Resources.getSystem().getIdentifier("next", "id", "android");
private static final int REW_BUTTON_ID = Resources.getSystem().getIdentifier("rew", "id", "android");
private static final int PAUSE_BUTTON_ID = Resources.getSystem().getIdentifier("pause", "id", "android");
private static final int MEDIACONTROLLER_PROGRESS_ID = Resources.getSystem().getIdentifier("mediacontroller_progress", "id", "android");
private static final int END_TIME_ID = Resources.getSystem().getIdentifier("time", "id", "android");
private static final int CURRENT_TIME_ID = Resources.getSystem().getIdentifier("time_current", "id", "android");
private AudioManager mAM;
private Runnable mLastSeekBarRunnable;
private boolean mDisableProgress = false;
private OnClickSpeedAdjustListener mOnClickSpeedAdjustListener;
public interface OnClickSpeedAdjustListener {
void onClickNormal();
void onClickFaster();
void onClickSlower();
}
public MediaController(Context context, AttributeSet attrs) {
super(context, attrs);
mRoot = this;
mFromXml = true;
initController(context);
}
public MediaController(Context context) {
super(context);
if (!mFromXml && initController(context))
initFloatingWindow();
}
public MediaController(Context context, boolean useFastForward, boolean disableProgressBar) {
this(context);
mUseFastForward = useFastForward;
mDisableProgress = disableProgressBar;
}
public MediaController(Context context, boolean useFastForward) {
this(context);
mUseFastForward = useFastForward;
}
public void refreshProgress() {
mProgress.setProgress(1000);
mCurrentTime.setText(generateTime(mDuration));
}
public void setOnClickSpeedAdjustListener(OnClickSpeedAdjustListener listener) {
mOnClickSpeedAdjustListener = listener;
}
private boolean initController(Context context) {
mUseFastForward = true;
mContext = context.getApplicationContext();
mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
return true;
}
@Override
public void onFinishInflate() {
if (mRoot != null)
initControllerView(mRoot);
super.onFinishInflate();
}
private void initFloatingWindow() {
mWindow = new PopupWindow(mContext);
mWindow.setFocusable(false);
mWindow.setBackgroundDrawable(null);
mWindow.setOutsideTouchable(true);
mAnimStyle = android.R.style.Animation;
}
/**
* Create the view that holds the widgets that control playback. Derived
* classes can override this to create their own.
*
* @return The controller view.
*/
protected View makeControllerView() {
return ((LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(MEDIA_CONTROLLER_ID, this);
}
private void initControllerView(View v) {
// By default these are hidden.
mPrevButton = (ImageButton) v.findViewById(PRV_BUTTON_ID);
if (mPrevButton != null) {
mPrevButton.setVisibility(View.GONE);
}
mNextButton = (ImageButton) v.findViewById(NEXT_BUTTON_ID);
if (mNextButton != null) {
mNextButton.setVisibility(View.GONE);
}
mFfwdButton = (ImageButton) v.findViewById(FFWD_BUTTON_ID);
if (mFfwdButton != null) {
mFfwdButton.setOnClickListener(mFfwdListener);
if (!mFromXml) {
mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
}
}
mRewButton = (ImageButton) v.findViewById(REW_BUTTON_ID);
if (mRewButton != null) {
mRewButton.setOnClickListener(mRewListener);
if (!mFromXml) {
mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
}
}
mPauseButton = (ImageButton) v.findViewById(PAUSE_BUTTON_ID);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mProgress = (ProgressBar) v.findViewById(MEDIACONTROLLER_PROGRESS_ID);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
seeker.setThumbOffset(1);
}
mProgress.setMax(1000);
mProgress.setEnabled(!mDisableProgress);
}
mEndTime = (TextView) v.findViewById(END_TIME_ID);
mCurrentTime = (TextView) v.findViewById(CURRENT_TIME_ID);
}
/**
* Control the action when the seekbar dragged by user
*
* @param seekWhenDragging
* True the media will seek periodically
*/
public void setInstantSeeking(boolean seekWhenDragging) {
mInstantSeeking = seekWhenDragging;
}
private void disableUnsupportedButtons() {
try {
if (mPauseButton != null && !mPlayer.canPause())
mPauseButton.setEnabled(false);
} catch (IncompatibleClassChangeError ex) {
}
}
/**
* <p>
* Change the animation style resource for this controller.
* </p>
*
* <p>
* If the controller is showing, calling this method will take effect only
* the next time the controller is shown.
* </p>
*
* @param animationStyle
* animation style to use when the controller appears and disappears.
* Set to -1 for the default animation, 0 for no animation,
* or a resource identifier for an explicit animation.
*
*/
public void setAnimationStyle(int animationStyle) {
mAnimStyle = animationStyle;
}
public interface OnShownListener {
public void onShown();
}
private OnShownListener mShownListener;
public void setOnShownListener(OnShownListener l) {
mShownListener = l;
}
public interface OnHiddenListener {
public void onHidden();
}
private OnHiddenListener mHiddenListener;
public void setOnHiddenListener(OnHiddenListener l) {
mHiddenListener = l;
}
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
long pos;
switch (msg.what) {
case FADE_OUT:
hide();
break;
case SHOW_PROGRESS:
if (!mPlayer.isPlaying()) {
return;
}
pos = setProgress();
if (pos == -1) {
return;
}
if (!mDragging && mShowing) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 50);
updatePausePlay();
}
break;
}
}
};
private long setProgress() {
if (mPlayer == null || mDragging) {
return 0;
}
long position = mPlayer.getCurrentPosition();
long duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration > 0) {
long pos = 1000L * position / duration;
mProgress.setProgress((int) pos);
}
int percent = mPlayer.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10);
}
mDuration = duration;
if (mEndTime != null)
mEndTime.setText(generateTime(mDuration));
if (mCurrentTime != null)
mCurrentTime.setText(generateTime(position));
return position;
}
private static String generateTime(long position) {
int totalSeconds = (int) (position / 1000);
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
if (hours > 0) {
return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes,
seconds).toString();
} else {
return String.format(Locale.US, "%02d:%02d", minutes, seconds)
.toString();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
show(sDefaultTimeout);
return true;
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
show(sDefaultTimeout);
return false;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0
&& (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
|| keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
show(sDefaultTimeout);
if (mPauseButton != null)
mPauseButton.requestFocus();
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_BACK
|| keyCode == KeyEvent.KEYCODE_MENU) {
hide();
return true;
} else {
show(sDefaultTimeout);
}
return super.dispatchKeyEvent(event);
}
private OnClickListener mPauseListener = new OnClickListener() {
public void onClick(View v) {
if (mOnClickSpeedAdjustListener != null) {
mOnClickSpeedAdjustListener.onClickNormal();
}
doPauseResume();
show(sDefaultTimeout);
}
};
private void updatePausePlay() {
if (mRoot == null || mPauseButton == null)
return;
if (mPlayer.isPlaying())
mPauseButton.setImageResource(IC_MEDIA_PAUSE_ID);
else
mPauseButton.setImageResource(IC_MEDIA_PLAY_ID);
}
private void doPauseResume() {
if (mPlayer.isPlaying())
mPlayer.pause();
else
mPlayer.start();
updatePausePlay();
}
private SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar bar) {
mDragging = true;
show(3600000);
mHandler.removeMessages(SHOW_PROGRESS);
if (mInstantSeeking)
mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
}
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
if (!fromuser) {
return;
}
final long newposition = (long) (mDuration * progress) / 1000;
String time = generateTime(newposition);
if (mInstantSeeking) {
mHandler.removeCallbacks(mLastSeekBarRunnable);
mLastSeekBarRunnable = new Runnable() {
@Override
public void run() {
mPlayer.seekTo(newposition);
}
};
mHandler.postDelayed(mLastSeekBarRunnable, SEEK_TO_POST_DELAY_MILLIS);
}
if (mCurrentTime != null)
mCurrentTime.setText(time);
}
public void onStopTrackingTouch(SeekBar bar) {
if (!mInstantSeeking)
mPlayer.seekTo(mDuration * bar.getProgress() / 1000);
show(sDefaultTimeout);
mHandler.removeMessages(SHOW_PROGRESS);
mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
mDragging = false;
mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
}
};
private OnClickListener mRewListener = new OnClickListener() {
public void onClick(View v) {
if (mOnClickSpeedAdjustListener != null) {
mOnClickSpeedAdjustListener.onClickSlower();
}
show(sDefaultTimeout);
}
};
private OnClickListener mFfwdListener = new OnClickListener() {
public void onClick(View v) {
if (mOnClickSpeedAdjustListener != null) {
mOnClickSpeedAdjustListener.onClickFaster();
}
show(sDefaultTimeout);
}
};
/**
* Set the view that acts as the anchor for the control view.
*
* - This can for example be a VideoView, or your Activity's main view.
* - AudioPlayer has no anchor view, so the view parameter will be null.
*
* @param view
* The view to which to anchor the controller when it is visible.
*/
@Override
public void setAnchorView(View view) {
mAnchor = view;
if (mAnchor == null) {
sDefaultTimeout = 0; // show forever
}
if (!mFromXml) {
removeAllViews();
mRoot = makeControllerView();
mWindow.setContentView(mRoot);
mWindow.setWidth(LayoutParams.MATCH_PARENT);
mWindow.setHeight(LayoutParams.WRAP_CONTENT);
}
initControllerView(mRoot);
}
@Override
public void setMediaPlayer(MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
@Override
public void show() {
show(sDefaultTimeout);
}
/**
* Show the controller on screen. It will go away automatically after
* 'timeout' milliseconds of inactivity.
*
* @param timeout
* The timeout in milliseconds. Use 0 to show the controller until hide() is called.
*/
@Override
public void show(int timeout) {
if (!mShowing) {
if (mAnchor != null && mAnchor.getWindowToken() != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
}
if (mPauseButton != null)
mPauseButton.requestFocus();
disableUnsupportedButtons();
if (mFromXml) {
setVisibility(View.VISIBLE);
} else {
int[] location = new int[2];
if (mAnchor != null) {
mAnchor.getLocationOnScreen(location);
Rect anchorRect = new Rect(location[0], location[1],
location[0] + mAnchor.getWidth(), location[1]
+ mAnchor.getHeight());
mWindow.setAnimationStyle(mAnimStyle);
mWindow.showAtLocation(mAnchor, Gravity.BOTTOM,
anchorRect.left, 0);
} else {
Rect anchorRect = new Rect(location[0], location[1],
location[0] + mRoot.getWidth(), location[1]
+ mRoot.getHeight());
mWindow.setAnimationStyle(mAnimStyle);
mWindow.showAtLocation(mRoot, Gravity.BOTTOM,
anchorRect.left, 0);
}
}
mShowing = true;
if (mShownListener != null)
mShownListener.onShown();
}
updatePausePlay();
mHandler.sendEmptyMessage(SHOW_PROGRESS);
if (timeout != 0) {
mHandler.removeMessages(FADE_OUT);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT),
timeout);
}
}
@Override
public boolean isShowing() {
return mShowing;
}
@Override
public void hide() {
if (mShowing) {
if (mAnchor != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
//mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
}
try {
mHandler.removeMessages(SHOW_PROGRESS);
if (mFromXml)
setVisibility(View.GONE);
else
mWindow.dismiss();
} catch (IllegalArgumentException ex) {
Log.d(TAG, "MediaController already removed");
}
mShowing = false;
if (mHiddenListener != null)
mHiddenListener.onHidden();
}
}
@Override
public void setEnabled(boolean enabled) {
if (mPauseButton != null) {
mPauseButton.setEnabled(enabled);
}
if (mFfwdButton != null) {
mFfwdButton.setEnabled(enabled);
}
if (mRewButton != null) {
mRewButton.setEnabled(enabled);
}
if (mProgress != null && !mDisableProgress)
mProgress.setEnabled(enabled);
disableUnsupportedButtons();
super.setEnabled(enabled);
}
public PopupWindow getWindow() {
return mWindow;
}
public long getSeekPosition() {
return mSeekPosition;
}
}

View File

@@ -0,0 +1,85 @@
package com.lzy.ninegrid.preview;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.lzy.ninegrid.ImageInfo;
import com.lzy.ninegrid.NineGridView;
import com.lzy.ninegrid.NineGridViewAdapter;
import java.io.Serializable;
import java.util.List;
/**
* ================================================
* 作 者:廖子尧
* 版 本1.0
* 创建日期2016/3/21
* 描 述:
* 修订历史:
* ================================================
*/
public class NineGridViewClickAdapter extends NineGridViewAdapter {
private int statusHeight;
public NineGridViewClickAdapter(Context context, List<ImageInfo> imageInfo) {
super(context, imageInfo);
statusHeight = getStatusHeight(context);
}
@Override
protected void onImageItemClick(Context context, NineGridView nineGridView, int index, List<ImageInfo> imageInfo) {
if (imageInfo.get(index).type == 2) {
Intent intent = new Intent(context, VideoPreviewActivity.class);
intent.putExtra("url", imageInfo.get(index).bigImageUrl);
context.startActivity(intent);
}else {
for (int i = 0; i < imageInfo.size(); i++) {
ImageInfo info = imageInfo.get(i);
View imageView;
if (i < nineGridView.getMaxSize()) {
imageView = nineGridView.getChildAt(i);
} else {
//如果图片的数量大于显示的数量,则超过部分的返回动画统一退回到最后一个图片的位置
imageView = nineGridView.getChildAt(nineGridView.getMaxSize() - 1);
}
info.imageViewWidth = imageView.getWidth();
info.imageViewHeight = imageView.getHeight();
int[] points = new int[2];
imageView.getLocationInWindow(points);
info.imageViewX = points[0];
info.imageViewY = points[1] - statusHeight;
}
Intent intent = new Intent(context, ImagePreviewActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable(ImagePreviewActivity.IMAGE_INFO, (Serializable) imageInfo);
bundle.putInt(ImagePreviewActivity.CURRENT_ITEM, index);
intent.putExtras(bundle);
context.startActivity(intent);
((Activity) context).overridePendingTransition(0, 0);
}
}
/**
* 获得状态栏的高度
*/
public int getStatusHeight(Context context) {
int statusHeight = -1;
try {
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
}

View File

@@ -0,0 +1,44 @@
package com.lzy.ninegrid.preview;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.lzy.ninegrid.R;
import com.pili.pldroid.player.widget.PLVideoView;
public class VideoPreviewActivity extends Activity {
private PLVideoView pLVideoView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preview_video);
pLVideoView = findViewById(R.id.pLVideoView);
String url = getIntent().getStringExtra("url");
pLVideoView.setVideoPath(url);
MediaController mMediaController = new MediaController(this);
pLVideoView.setMediaController(mMediaController);
pLVideoView.start();
}
@Override
protected void onResume() {
super.onResume();
pLVideoView.start();
}
@Override
protected void onPause() {
super.onPause();
pLVideoView.pause();
}
@Override
protected void onDestroy() {
super.onDestroy();
pLVideoView.stopPlayback();
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/ic_default_bg_color"/>
</shape>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.lzy.ninegrid.preview.HackyViewPager
android:id="@+id/viewPager2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/tv_pager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:text="1/4"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:background="@android:color/black"
android:layout_height="match_parent">
<com.pili.pldroid.player.widget.PLVideoView
android:id="@+id/pLVideoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
</LinearLayout>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<uk.co.senab.photoview.PhotoView
android:id="@+id/pv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ProgressBar
android:id="@+id/pb"
style="@style/Widget.AppCompat.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"/>
</FrameLayout>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="MissingDefaultResource">
<ImageView
android:layout_gravity="center"
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.pili.pldroid.player.widget.PLVideoView
android:id="@+id/pv"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="NineGridView">
<attr name="ngv_singleImageSize" format="dimension"/>
<attr name="ngv_singleImageRatio" format="float"/>
<attr name="ngv_gridSpacing" format="dimension"/>
<attr name="ngv_maxSize" format="integer"/>
<attr name="ngv_mode" format="enum">
<enum name="fill" value="0"/>
<enum name="grid" value="1"/>
</attr>
</declare-styleable>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_default_bg_color">#33000000</color>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="select2">%1$s/%2$s</string>
</resources>