Photo Widget своими руками

public class WidgetView extends View { ContentObserver observer; GestureDetector gd; Scroller scroller; NinePatchDrawable frame; Bitmap loading; Bitmap broken; Item[] items = null; float touchLastY = 0; float touchDownY = 0; boolean touchTap = false; boolean touchScroll = false; long loaderId = -1; int getScrollY = 0; int width = 160; int height = 200; public WidgetView (Context context) { super (context); gd = new GestureDetector (context, new GestureListener ()); scroller = new Scroller (context); observer = new ContentObserver (new Handler ()){ @Override public void onChange (boolean selfChange){ super.onChange (selfChange); loadThumbnails (); } }; frame = (NinePatchDrawable)getResources ().getDrawable (R.drawable.frame); loading = getBmp (R.drawable.loading); broken = getBmp (R.drawable.broken); } @Override public void onAttachedToWindow (){ super.onAttachedToWindow (); loadThumbnails (); getContext ().getContentResolver ().registerContentObserver (MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, observer); getContext ().getContentResolver ().registerContentObserver (MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true, observer); } @Override public void onDetachedFromWindow (){ super.onDetachedFromWindow (); getContext ().getContentResolver ().unregisterContentObserver (observer); } @Override protected void onDraw (Canvas canvas){ super.onDraw (canvas); Paint p = new Paint (); p.setDither (true); p.setFilterBitmap (true); int pos = getSelected (); float percent = getSelectedPercent (); if (items!= null){ if (items.length == 0){ Bitmap camera = getBmp (R.drawable.camera); Transformation transform = new Transformation (0, percent, 160, 140); p.setAlpha (transform.alpha); canvas.drawBitmap (camera, transform.matrix3d, p); return; } if (pos >= 1){ if (items[pos-1] != null){ if (items[pos-1].thumbnail!= null){ Bitmap thumbnail = items[pos-1].thumbnail; Transformation transform = new Transformation (-1, percent, thumbnail.getWidth (), thumbnail.getHeight ()); p.setAlpha (transform.alpha); canvas.drawBitmap (thumbnail, transform.matrix3d, p); } else { Transformation transform = new Transformation (-1, percent, broken.getWidth (), broken.getHeight ()); p.setAlpha (transform.alpha); canvas.drawBitmap (broken, transform.matrix3d, p); } } else { Transformation transform = new Transformation (-1, percent, loading.getWidth (), loading.getHeight ()); p.setAlpha (transform.alpha); canvas.drawBitmap (loading, transform.matrix3d, p); } } if (items.length-1 >= pos+1){ if (items[pos+1] != null){ if (items[pos+1].thumbnail!= null){ Bitmap thumbnail = items[pos+1].thumbnail; Transformation transform = new Transformation (1, percent, thumbnail.getWidth (), thumbnail.getHeight ()); p.setAlpha (transform.alpha); canvas.drawBitmap (thumbnail, transform.matrix3d, p); } else { Transformation transform = new Transformation (1, percent, broken.getWidth (), broken.getHeight ()); p.setAlpha (transform.alpha); canvas.drawBitmap (broken, transform.matrix3d, p); } } else { Transformation transform = new Transformation (1, percent, loading.getWidth (), loading.getHeight ()); p.setAlpha (transform.alpha); canvas.drawBitmap (loading, transform.matrix3d, p); } } if (items.length-1 >= pos){ if (items[pos] != null){ if (items[pos].thumbnail!= null){ Bitmap thumbnail = items[pos].thumbnail; Transformation transform = new Transformation (0, percent, thumbnail.getWidth (), thumbnail.getHeight ()); p.setAlpha (transform.alpha); canvas.drawBitmap (thumbnail, transform.matrix3d, p); } else { Transformation transform = new Transformation (0, percent, broken.getWidth (), broken.getHeight ()); p.setAlpha (transform.alpha); canvas.drawBitmap (broken, transform.matrix3d, p); } } else { Transformation transform = new Transformation (0, percent, loading.getWidth (), loading.getHeight ()); p.setAlpha (transform.alpha); canvas.drawBitmap (loading, transform.matrix3d, p); } } } else { Transformation transform = new Transformation (0, 0, loading.getWidth (), loading.getHeight ()); canvas.drawBitmap (loading, transform.matrix3d, null); } } @Override public boolean onTouchEvent (MotionEvent me) { if (items == null) return true; gd.onTouchEvent (me); float touchY = me.getY (); if (me.getAction () == MotionEvent.ACTION_DOWN){ if (! scroller.isFinished ()){ scroller.abortAnimation (); } else { touchTap = true; touchScroll = false; } touchDownY = touchLastY = touchY; } else if (me.getAction () == MotionEvent.ACTION_MOVE){ if (Math.abs (touchY — touchDownY) > ViewConfiguration.getTouchSlop () || touchScroll){ getParent ().requestDisallowInterceptTouchEvent (true); touchTap = false; touchScroll = true; getScrollY += -(int)(touchY — touchLastY); computeOverscroll (); } touchLastY = touchY; } else if ((me.getAction () == MotionEvent.ACTION_UP || me.getAction () == MotionEvent.ACTION_CANCEL) && scroller.isFinished ()){ if (touchTap && me.getAction () == MotionEvent.ACTION_UP){ tap (); } setSelected (getSelected (), true); getParent ().requestDisallowInterceptTouchEvent (false); } return true; } @Override public void computeScroll (){ if (scroller.computeScrollOffset ()){ int oldY = getScrollY; getScrollY = scroller.getCurrY (); if (oldY!= getScrollY){ onScrollChanged (0, getScrollY, 0, oldY); } if (scroller.getFinalY () == getScrollY){ scroller.abortAnimation (); setSelected (getSelected (), true); } postInvalidate (); } } @Override protected void onMeasure (int wms, int hms){ width = MeasureSpec.getSize (wms); height = MeasureSpec.getSize (hms); super.onMeasure (wms, hms); } @Override protected void onSizeChanged (int w, int h, int oldw, int oldh){ width = w; height = h; super.onSizeChanged (w, h, oldw, oldh); } void loadThumbnails (){ items = null; getScrollY = 0; invalidate (); Thread loader = new Thread (new Runnable () { public void run () { long currentId = Thread.currentThread ().getId (); try{ final ArrayList list = mediaList (); if (list == null || loaderId!= currentId) return; items = new Item[list.size ()]; postInvalidate (); for (int i=0; i Math.max (items.length-1, 0)*140+50){ getScrollY = Math.max (items.length-1, 0)*140+50; } invalidate (); } void tap (){ try{ if (items!= null){ if (items.length == 0){ Intent i = new Intent («android.media.action.IMAGE_CAPTURE»); i.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); getContext ().startActivity (i); return; } if (items[getSelected ()] == null) return; int type = items[getSelected ()].type; String path = items[getSelected ()].path; if (type == 1){ Intent view = new Intent (android.content.Intent.ACTION_VIEW); File imageFile = new File (path); view.setDataAndType (Uri.fromFile (imageFile), «image/*»); view.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); getContext ().startActivity (view); } else if (type == 2){ Intent view = new Intent (android.content.Intent.ACTION_VIEW); File imageFile = new File (path); view.setDataAndType (Uri.fromFile (imageFile), «video/*»); view.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); getContext ().startActivity (view); } } } catch (Exception e){} } ArrayList mediaList (){ try{ ArrayList list = new ArrayList(); Cursor c = getContext ().getContentResolver ().query (MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_ADDED}, null, null, null); if (c.moveToFirst ()){ do{ list.add (new MediaItem (c.getString (c.getColumnIndexOrThrow (MediaStore.Images.Media.DATA)), c.getString (c.getColumnIndexOrThrow (MediaStore.Images.Media.DATE_ADDED)), 1)); } while (c.moveToNext ()); } c.close (); c = getContext ().getContentResolver ().query (MediaStore.Video.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Video.Media.DATA, MediaStore.Video.Media.DATE_ADDED}, null, null, null); if (c.moveToFirst ()){ do{ list.add (new MediaItem (c.getString (c.getColumnIndexOrThrow (MediaStore.Video.Media.DATA)), c.getString (c.getColumnIndexOrThrow (MediaStore.Video.Media.DATE_ADDED)), 2)); } while (c.moveToNext ()); } c.close (); Collections.sort (list, new Comparator(){ @Override public int compare (MediaItem mi1, MediaItem mi2) { return mi1.date.compareToIgnoreCase (mi2.date); } }); Collections.reverse (list); return list; } catch (Exception e){ return new ArrayList(); } } Bitmap getBmp (MediaItem mi){ try{ Paint p = new Paint (); p.setDither (true); p.setFilterBitmap (true); if (mi.type == 1){ int rot = 0; try{ ExifInterface rote = new ExifInterface (mi.path); int r = rote.getAttributeInt (ExifInterface.TAG_ORIENTATION, 1); if (r == 3){ rot = 180; } else if (r == 8){ rot = 270; } else if (r == 6){ rot = 90; } else { rot = 0; } } catch (Exception e){} BitmapFactory.Options bfo = new BitmapFactory.Options (); bfo.inJustDecodeBounds = true; BitmapFactory.decodeFile (mi.path, bfo); if (rot == 90 || rot == 270){ bfo.inSampleSize = Math.min (bfo.outWidth/140, bfo.outHeight/120); } else { bfo.inSampleSize = Math.max (bfo.outWidth/140, bfo.outHeight/120); } bfo.inJustDecodeBounds = false; Bitmap src = BitmapFactory.decodeFile (mi.path, bfo); if (rot!= 0){ Matrix m = new Matrix (); m.postRotate (rot); src = Bitmap.createBitmap (src, 0, 0, src.getWidth (), src.getHeight (), m, true); } float aspect = (float)src.getWidth ()/src.getHeight (); int image_w = 160; int image_h = 140; if (aspect > 1){ image_h = (int)((image_w-20)/aspect+20); } else { image_w = (int)((image_h-20)*aspect+20); } Bitmap result = Bitmap.createBitmap (image_w, image_h, Config.ARGB_8888); Canvas c = new Canvas (result); frame.setBounds (0, 0, image_w, image_h); frame.draw©; c.drawBitmap (src, null, new RectF (10, 10, image_w-10, image_h-10), p); return result; } else if (mi.type == 2){ Bitmap src = ThumbnailUtils.createVideoThumbnail (mi.path, MediaStore.Video.Thumbnails.MINI_KIND); float aspect = (float)src.getWidth ()/src.getHeight (); int image_w = 160; int image_h = (int)((image_w-20)/aspect+20); Bitmap result = Bitmap.createBitmap (image_w, image_h, Config.ARGB_8888); Canvas c = new Canvas (result); frame.setBounds (0, 0, image_w, image_h); frame.draw©; c.drawBitmap (src, null, new RectF (10, 10, image_w-10, image_h-10), p); c.drawBitmap (BitmapFactory.decodeResource (getResources (), R.drawable.video), (image_w-64)/2, (image_h-64)/2, p); return result; } } catch (Exception e){ return null; } catch (OutOfMemoryError e){ return null; } return null; } Bitmap getBmp (int res){ Bitmap bmp = Bitmap.createBitmap (160, 140, Config.ARGB_8888); Canvas c = new Canvas (bmp); Paint p = new Paint (); p.setDither (true); p.setFilterBitmap (true); frame.setBounds (0, 0, 160, 140); frame.draw©; c.drawBitmap (BitmapFactory.decodeResource (getResources (), res), 48, 38, p); return bmp; } public class MediaItem { String path; String date; int type; public MediaItem (String str1, String str2, int i){ path = str1; date = str2; type = i; } } public class Item { String path; Bitmap thumbnail; int type; public Item (String str, Bitmap bmp, int i){ path = str; thumbnail = bmp; type = i; } } public class Transformation { Matrix matrix3d; int alpha; public Transformation (int pos, float percent, int imageWidth, int imageHeight){ float centerX = (float)width/2; float centerY = (float)height/2; float f = -pos + percent; centerY -= (float)Math.sin (f*Math.PI/2)*40; float f1 = Math.abs (f) — 0.5f; if (f1 < 0) f1 = 0; float f2 = Math.abs(f) / 1.5f; alpha = 255 - (int)(255*f1); float scale = (float) (1 - 0.4*f2); Camera c = new Camera(); matrix3d = new Matrix(); c.save(); float rotate = percent*100; if(pos == 0) rotate *= -1; c.rotateX(rotate); c.getMatrix(matrix3d); matrix3d.preTranslate(-imageWidth/2, -imageHeight/2); matrix3d.postScale(scale, scale); matrix3d.postTranslate(centerX, centerY); c.restore(); } } private class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onFling(MotionEvent me1, MotionEvent me2, float vX, float vY){ scroller.fling(0, getScrollY, 0, -(int)vY, 0, 0, -50, Math.max(items.length-1, 0)*140+50); invalidate(); return true; } } }

© Habrahabr.ru