这个类便是窗口Dialog的主体成分了:mImages接受Glide就是支持图片设置格式,比如网络地址,本地地址,内存地址等
mPageTransformer设置viewpager滑动时的特效,像缩放、3D都可以自定义设置的
instance 单例设计模式
mIsCancel是否取消
mIsTransparent背景是否透明,其实可是获取window,设置一个透明度
roundSize设置圆角大小
方法返回this方便可以链式调用
public class MyItHeiMaDialog extends DialogFragment { public Object[] mImages; private ViewPager.PageTransformer mPageTransformer; public static MyItHeiMaDialog instance = null; private boolean mIsCancel; private boolean mIsTransparent; private int roundSize=10; public MyItHeiMaDialog() {} public static MyItHeiMaDialog getInstance() { if (instance == null) { instance = new MyItHeiMaDialog(); } return instance; } public MyItHeiMaDialog setImages(Object...images) { mImages = images; return this; } public MyItHeiMaDialog setRoundSize(int roundSize ) { this.roundSize = roundSize; return this; } public MyItHeiMaDialog setPageTransformer(ViewPager.PageTransformer pageTransformer) { mPageTransformer = pageTransformer; return this; } public MyItHeiMaDialog show(FragmentManager fragmentManager) { if (instance != null) { instance.show(fragmentManager, "QiShuiFragmentManager"); } return this; } /** * 点击四周是否取消dialog,默认取消 * @param isCancel * @return */ public MyItHeiMaDialog setCanceledOnTouchOutside(boolean isCancel) { mIsCancel = isCancel; return this; } /** * 设置背景四周是否透明,调用时需要放到show方法后面 * @param isTransparent * @return */ public MyItHeiMaDialog setOutsideIsTransparent(boolean isTransparent) { mIsTransparent = isTransparent; return this; } public MyItHeiMaDialog dissmiss() { getDialog().dismiss(); return this; } /** * @param inflater * @param container * @param savedInstanceState * @return */ @Nullable @Override public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) { getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); if (mIsCancel) { getDialog().setCanceledOnTouchOutside(mIsCancel); } View view = inflater.inflate(R.layout.fragment_dialog, container); MyViewPager viewPager = (MyViewPager) view.findViewById(R.id.viewpager); CircleIndicatorView indicator = (CircleIndicatorView) view.findViewById(R.id.indicator); viewPager.setPageTransformer(true, mPageTransformer); viewPager.setAdapter(new QiShuiPagerAdapter()); indicator.setUpWithViewPager(viewPager); indicator.setEnableClickSwitch(false); // 设置指示器间距 indicator.setSpace(indicator.dpToPx(10)); return view; } @Override public void onStart() { super.onStart(); if (mIsTransparent) { Window window = getDialog().getWindow(); WindowManager.LayoutParams windowParams = window.getAttributes(); windowParams.dimAmount = 0.0f; window.setAttributes(windowParams); } } class QiShuiPagerAdapter extends PagerAdapter { @Override public int getCount() { return mImages.length; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { View inflate = View.inflate(container.getContext(),R.layout.guide_pager_img, null); ImageView imageView = (ImageView) inflate.findViewById(R.id.iv_item_guide_img); Glide.with(container.getContext()).load(mImages[position]).error(R.mipmap.ic_launcher).placeholder(R.mipmap.defaultimg).transform(new GlideRoundTransform(container.getContext(),roundSize)).into(imageView); container.addView(inflate); return inflate; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); } } }
fragment_dialog.xml主体布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:qishui="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="vertical"> <com.qishui.zhou.rv2.dialog.CircleIndicatorView android:id="@+id/indicator" android:layout_width="match_parent" android:layout_height="48dp" android:layout_gravity="right" android:layout_marginBottom="20dp" qishui:fill_mode="number" /> <com.qishui.zhou.rv2.dialog.MyViewPager android:id="@+id/viewpager" android:layout_width="330dp" android:layout_height="440dp"> </com.qishui.zhou.rv2.dialog.MyViewPager> </LinearLayout>
自定义CircleIndicatorView.class方便控制小圆点
public class CircleIndicatorView extends View implements ViewPager.OnPageChangeListener{ private static final String LETTER[] = new String[]{"A","B","C","D","E","F","G","H","I","G","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}; // private int mSelectColor = Color.parseColor("#E38A7C"); private int mSelectColor = Color.parseColor("#FFFFFF"); private Paint mCirclePaint; private Paint mTextPaint; private int mCount; // indicator 的数量 private int mRadius;//半径 private int mStrokeWidth;//border private int mTextColor;// 小圆点中文字的颜色 private int mDotNormalColor;// 小圆点默认颜色 private int mSpace = 0;// 圆点之间的间距 private List<Indicator> mIndicators; private int mSelectPosition = 0; // 选中的位置 private FillMode mFillMode = FillMode.NONE;// 默认只有小圆点 private ViewPager mViewPager; private OnIndicatorClickListener mOnIndicatorClickListener; /** * 是否允许点击Indicator切换ViewPager */ private boolean mIsEnableClickSwitch = false; public CircleIndicatorView(Context context) { super(context); init(); } public CircleIndicatorView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); getAttr(context,attrs); init(); } public CircleIndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); getAttr(context,attrs); init(); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public CircleIndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); getAttr(context,attrs); init(); } private void init(){ mCirclePaint = new Paint(); mCirclePaint.setDither(true); mCirclePaint.setAntiAlias(true); mCirclePaint.setStyle(Paint.Style.FILL_AND_STROKE); mTextPaint = new Paint(); mTextPaint.setDither(true); mTextPaint.setAntiAlias(true); // 默认值 mIndicators = new ArrayList<>(); initValue(); } private void initValue(){ mCirclePaint.setColor(mDotNormalColor); mCirclePaint.setStrokeWidth(mStrokeWidth); mTextPaint.setColor(mTextColor); mTextPaint.setTextSize(mRadius); } /** * 获取自定义属性 * @param context * @param attrs */ private void getAttr(Context context,AttributeSet attrs){ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleIndicatorView); mRadius = (int) typedArray.getDimensionPixelSize(R.styleable.CircleIndicatorView_indicatorRadius,dpToPx(6)); mStrokeWidth = (int) typedArray.getDimensionPixelSize(R.styleable.CircleIndicatorView_indicatorBorderWidth,dpToPx(2)); mSpace = typedArray.getDimensionPixelSize(R.styleable.CircleIndicatorView_indicatorSpace,dpToPx(5)); // color mTextColor = typedArray.getColor(R.styleable.CircleIndicatorView_indicatorTextColor,Color.BLACK); mSelectColor = typedArray.getColor(R.styleable.CircleIndicatorView_indicatorSelectColor,Color.WHITE); mDotNormalColor = typedArray.getColor(R.styleable.CircleIndicatorView_indicatorColor,Color.GRAY); mIsEnableClickSwitch = typedArray.getBoolean(R.styleable.CircleIndicatorView_enableIndicatorSwitch,false); int fillMode = typedArray.getInt(R.styleable.CircleIndicatorView_fill_mode,2); if(fillMode == 0){ mFillMode = FillMode.LETTER; }else if(fillMode == 1){ mFillMode = FillMode.NUMBER; }else{ mFillMode = FillMode.NONE; } typedArray.recycle(); } /** * 测量每个圆点的位置 */ private void measureIndicator(){ mIndicators.clear(); float cx = 0; for(int i=0;i<mCount;i++){ Indicator indicator = new Indicator(); if( i== 0){ cx = mRadius + mStrokeWidth; }else{ cx += (mRadius + mStrokeWidth) * 2 +mSpace; } indicator.cx = cx; indicator.cy = getMeasuredHeight() / 2; mIndicators.add(indicator); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = (mRadius+mStrokeWidth)* 2 * mCount + mSpace *(mCount - 1); int height = mRadius * 2 + mSpace * 2; setMeasuredDimension(width,height); measureIndicator(); } @Override protected void onDraw(Canvas canvas) { for(int i=0;i<mIndicators.size();i++){ Indicator indicator = mIndicators.get(i); float x = indicator.cx; float y = indicator.cy; if(mSelectPosition == i){ mCirclePaint.setStyle(Paint.Style.FILL); mCirclePaint.setColor(mSelectColor); }else{ mCirclePaint.setColor(mDotNormalColor); if(mFillMode != FillMode.NONE){ mCirclePaint.setStyle(Paint.Style.STROKE); }else{ mCirclePaint.setStyle(Paint.Style.FILL); } } canvas.drawCircle(x,y, mRadius, mCirclePaint); // 绘制小圆点中的内容 if(mFillMode != FillMode.NONE){ String text = ""; if(mFillMode == FillMode.LETTER){ if(i >= 0 && i<LETTER.length){ text = LETTER[i]; } }else{ text = String.valueOf(i+1); } Rect bound = new Rect(); mTextPaint.getTextBounds(text,0,text.length(),bound); int textWidth = bound.width(); int textHeight = bound.height(); float textStartX = x - textWidth / 2; float textStartY = y + textHeight / 2; canvas.drawText(text,textStartX,textStartY, mTextPaint); } } } @Override public boolean onTouchEvent(MotionEvent event) { float xPoint = 0; float yPoint = 0; switch (event.getAction()){ case MotionEvent.ACTION_DOWN: xPoint = event.getX(); yPoint = event.getY(); handleActionDown(xPoint,yPoint); break; } return super.onTouchEvent(event); } private void handleActionDown(float xDis,float yDis){ for(int i=0;i<mIndicators.size();i++){ Indicator indicator = mIndicators.get(i); if(xDis < (indicator.cx + mRadius+mStrokeWidth) && xDis >=(indicator.cx - (mRadius + mStrokeWidth)) && yDis >= (yDis - (indicator.cy+mStrokeWidth)) && yDis <(indicator.cy+mRadius+mStrokeWidth)){ // 找到了点击的Indicator // 是否允许切换ViewPager int temp= mViewPager.getCurrentItem(); Log.e("handleActionDown",temp+"::"+i+mIsEnableClickSwitch); if(mIsEnableClickSwitch){ mViewPager.setCurrentItem(i,false); } // 回调 if(mOnIndicatorClickListener!=null){ mOnIndicatorClickListener.onSelected(i); } break; } } } public void setOnIndicatorClickListener(OnIndicatorClickListener onIndicatorClickListener) { mOnIndicatorClickListener = onIndicatorClickListener; } private void setCount(int count) { mCount = count; invalidate(); } /** * 设置 border * @param borderWidth */ public void setBorderWidth(int borderWidth){ mStrokeWidth = borderWidth; initValue(); } /** * 设置文字的颜色 * @param textColor */ public void setTextColor(int textColor) { mTextColor = textColor; initValue(); } /** * 设置选中指示器的颜色 * @param selectColor */ public void setSelectColor(int selectColor) { mSelectColor = selectColor; } /** * 设置指示器默认颜色 * @param dotNormalColor */ public void setDotNormalColor(int dotNormalColor) { mDotNormalColor = dotNormalColor; initValue(); } /** * 设置选中的位置 * @param selectPosition */ public void setSelectPosition(int selectPosition) { mSelectPosition = selectPosition; } /** * 设置Indicator 模式 * @param fillMode */ public void setFillMode(FillMode fillMode) { mFillMode = fillMode; } /** * 设置Indicator 半径 * @param radius */ public void setRadius(int radius) { mRadius = radius; initValue(); } public void setSpace(int space) { mSpace = space; } public void setEnableClickSwitch(boolean enableClickSwitch){ mIsEnableClickSwitch = enableClickSwitch; } /** * 与ViewPager 关联 * @param viewPager */ public void setUpWithViewPager(ViewPager viewPager){ releaseViewPager(); if(viewPager == null){ return; } mViewPager = viewPager; mViewPager.addOnPageChangeListener(this); int count = mViewPager.getAdapter().getCount(); setCount(count); } /** * 重置ViewPager */ private void releaseViewPager(){ if(mViewPager!=null){ mViewPager.removeOnPageChangeListener(this); mViewPager = null; } } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { mSelectPosition = position; invalidate(); } @Override public void onPageScrollStateChanged(int state) { } /** * Indicator 点击回调 */ public interface OnIndicatorClickListener{ public void onSelected(int position); } public static class Indicator{ public float cx; // 圆心x坐标 public float cy; // 圆心y 坐标 } public enum FillMode{ LETTER, NUMBER, NONE } public int dpToPx(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics()); } public int pxToDp(float px) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px, Resources.getSystem().getDisplayMetrics()); } }
attr.xml定义自定义属性
<declare-styleable name="CircleIndicatorView"> <attr name="indicatorRadius" format="dimension"/> <attr name="indicatorBorderWidth" format="dimension"/> <attr name="indicatorSpace" format="dimension"/> <attr name="indicatorTextColor" format="color"/> <attr name="indicatorColor" format="color"/> <attr name="indicatorSelectColor" format="color"/> <attr name="enableIndicatorSwitch" format="boolean"/> <attr name="fill_mode"> <enum name="letter" value="0"/> <enum name="number" value="1"/> <enum name="none" value="2"/> </attr> </declare-styleable>
自定义MyViewPager 主要是PhotoView在使用多点触碰时重写onInterceptTouchEvent方法,其中 E/MotionEvent-JNI(533): validatePointerIndex pointerIndex:-1, pointerCount:1是android系统处理时抛出的异常,不影响项目。
public class MyViewPager extends ViewPager { public MyViewPager(Context context) { super(context); } public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { return super.onInterceptTouchEvent(ev); } catch (IllegalArgumentException e) { e.printStackTrace(); return false; } } }
下面的这部分代码这些核心
View inflate = View.inflate(container.getContext(),R.layout.guide_pager_img, null);
ImageView imageView = (ImageView) inflate.findViewById(R.id.iv_item_guide_img);
Glide.with(container.getContext()).load(mImages[position]).error(R.mipmap.ic_launcher).placeholder(R.mipmap.defaultimg).transform(new GlideRoundTransform(container.getContext(),roundSize)).into(imageView);
container.addView(inflate);
return inflate;
guide_pager_img.xml就是View的具体条目,viewpager是装载这些的容器。下面这是引入放大、移动的框架PhotoView;布局简单只有一张图片。当然可以使用线性或者其他布局添加其他控件,如TextView等。
<?xml version="1.0" encoding="utf-8"?> <uk.co.senab.photoview.PhotoView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/iv_item_guide_img" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" />
GlideRoundTransform设置圆角图片,也可定义其他如高斯模糊处理、灰度处理
public class GlideRoundTransform extends BitmapTransformation { private static float radius = 0f; public GlideRoundTransform(Context context) { this(context, 6); } public GlideRoundTransform(Context context, int dp) { super(context); this.radius = Resources.getSystem().getDisplayMetrics().density * dp; } @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { return roundCrop(pool, toTransform); } private static Bitmap roundCrop(BitmapPool pool, Bitmap source) { if (source == null) return null; Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); if (result == null) { result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); } Canvas canvas = new Canvas(result); Paint paint = new Paint(); paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); paint.setAntiAlias(true); RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight()); canvas.drawRoundRect(rectF, radius, radius, paint); return result; } @Override public String getId() { return getClass().getName() + Math.round(radius); } }
使用之前需要添加依赖
compile 'com.github.chrisbanes.photoview:library:1.2.4' compile 'com.github.bumptech.glide:glide:3.5.2'
最后是常见的viewpager切换动画
public class DepthPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.75f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 0) { // [-1,0] // Use the default slide transition when moving to the left page view.setAlpha(1); view.setTranslationX(0); view.setScaleX(1); view.setScaleY(1); } else if (position <= 1) { // (0,1] // Fade the page out. view.setAlpha(1 - position); // Counteract the default slide transition view.setTranslationX(pageWidth * -position); // Scale the page down (between MIN_SCALE and 1) float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } }
public class ZoomOutPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.85f; private static final float MIN_ALPHA = 0.5f; @SuppressLint("NewApi") public void transformPage(View view, float position) { int pageWidth = view.getWidth(); int pageHeight = view.getHeight(); Log.e("TAG", view + " , " + position + ""); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 1) //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0 { // [-1,1] // Modify the default slide transition to shrink the page as well float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); float vertMargin = pageHeight * (1 - scaleFactor) / 2; float horzMargin = pageWidth * (1 - scaleFactor) / 2; if (position < 0) { view.setTranslationX(horzMargin - vertMargin / 2); } else { view.setTranslationX(-horzMargin + vertMargin / 2); } // Scale the page down (between MIN_SCALE and 1) view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); // Fade the page relative to its size. view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } }
最后的最后便是这样使用
public class ThriedActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thired); final String url1 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1497030226348&di=6ec62de4ff25d9d015b701fe4deb09f2&imgtype=0&src=http%3A%2F%2Fimage.tianjimedia.com%2FuploadImages%2F2015%2F204%2F22%2FYMG9CAUWUM15.jpg"; final String url2 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1497030227637&di=f5abdcaa2264dffe29ff9127c1a760ad&imgtype=0&src=http%3A%2F%2Fuserimage7.360doc.com%2F16%2F0123%2F23%2F6622010_201601232355360953727142.jpg"; Button btn = (Button) findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MyItHeiMaDialog.getInstance() .setImages(url1, R.mipmap.image2, R.mipmap.image1, url2) .setRoundSize(20) .setPageTransformer(new DepthPageTransformer()) .show(getSupportFragmentManager()); } }); } }
传入的图片参数可以混合;如果使用网络那么需要设置权限
<uses-permission android:name="android.permission.INTERNET"></uses-permission> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
该项目其实是其他控件组合而来
指示器
http://www.jianshu.com/p/7833d8450405
主体部分
http://www.jianshu.com/p/b2847a18046b
photoView
Glide
本项目下载地址
https://github.com/Qishuichixi/FragmentDialog
百度云地址
晚安,该睡了....2017年6月10日01:03:15