Wednesday, August 30, 2017

Drag/Scroll canvas not smooth after zoom [android coloring book app]

Leave a Comment

I'm trying to implement zoom feature in my coloring book app, the zoom working perfectly but I have 3 main problems in canvas after zoom:

  1. Drag/scroll the canvas is not smooth and difficult after zoom.
  2. I can't detect the pinch motion in order to avoid coloring during zoom process.
  3. After zoom it is not filling the exact tapped point so I would like to keep filling the tapped point.

Here is my code:

public class MainActivity extends AppCompatActivity implements View.OnTouchListener, View.OnClickListener { private static final int PERMISSION_REQUEST_CODE = 1; public static ArrayList<Point> drawnPoints = new ArrayList<Point>();  Paint paint; ImageView iv; int position, code; Button White, Black, Gray, lightOrange, Brown, Yellow, deepBlue, lightBlue, deepPurple, lightPurple,         deepGreen, lightGreen, deepPink, lightPink, Red, deepOrange; int h, w; Drawable drawable; private RelativeLayout drawingLayout; private MyView myView; private ArrayList<Path> paths = new ArrayList<Path>(); private InterstitialAd mInterstitialAd;  @Override public void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);     getSupportActionBar().setDisplayHomeAsUpEnabled(true);      NativeExpressAdView adView = (NativeExpressAdView) findViewById(R.id.adView);     AdRequest request = new AdRequest.Builder().build();     adView.loadAd(request);     mInterstitialAd = new InterstitialAd(this);     mInterstitialAd.setAdUnitId(getString(R.string.interstitial_unit_id));     requestNewInterstitial();     mInterstitialAd.setAdListener(new AdListener() {         @Override         public void onAdLoaded() {             if (mInterstitialAd.isLoaded()) {                 mInterstitialAd.show();             }         }      });     iv = (ImageView) findViewById(R.id.coringImage);      Bundle extras = getIntent().getExtras();     if (extras != null) {         // code of category         //position of image in the category array         position = extras.getInt("position");         code = extras.getInt("code");     }      drawingLayout = (RelativeLayout) findViewById(R.id.relative_layout);     White = (Button) findViewById(R.id.white);     Black = (Button) findViewById(R.id.black);     Gray = (Button) findViewById(R.id.gray);     lightOrange = (Button) findViewById(R.id.light_orange);     Brown = (Button) findViewById(R.id.brown);     Yellow = (Button) findViewById(R.id.yellow);     deepBlue = (Button) findViewById(R.id.deep_blue);     lightBlue = (Button) findViewById(R.id.light_blue);     deepPurple = (Button) findViewById(R.id.deep_purple);     lightPurple = (Button) findViewById(R.id.light_purple);     deepGreen = (Button) findViewById(R.id.deep_green);     lightGreen = (Button) findViewById(R.id.light_green);     deepPink = (Button) findViewById(R.id.deep_pink);     lightPink = (Button) findViewById(R.id.light_pink);     Red = (Button) findViewById(R.id.red);     deepOrange = (Button) findViewById(R.id.deep_orange);      White.setOnClickListener(this);     Black.setOnClickListener(this);     Gray.setOnClickListener(this);     lightOrange.setOnClickListener(this);     Brown.setOnClickListener(this);     Yellow.setOnClickListener(this);     deepBlue.setOnClickListener(this);     lightBlue.setOnClickListener(this);     deepPurple.setOnClickListener(this);     lightPurple.setOnClickListener(this);     deepGreen.setOnClickListener(this);     lightGreen.setOnClickListener(this);     deepPink.setOnClickListener(this);     lightPink.setOnClickListener(this);     Red.setOnClickListener(this);     deepOrange.setOnClickListener(this);      myView = new MyView(this);     drawingLayout.addView(myView);  }  @Override public boolean onTouch(View v, MotionEvent event) {     // TODO Auto-generated method stub     return false; }  //MeunItems @Override public boolean onCreateOptionsMenu(Menu menu) {     // Inflate the menu; this adds items to the action bar if it is present.     getMenuInflater().inflate(R.menu.share_save_menu, menu);     return true; }  @Override public boolean onOptionsItemSelected(MenuItem item) {     switch (item.getItemId()) {         case R.id.action_share:             onShareImageItem();             break;         case R.id.action_save:             if (Build.VERSION.SDK_INT >= 23) {                 if (checkPermission()) {                     save(myView);                  } else {                     requestPermission(); // Code for permission                 }             } else {                 // Code for Below 23 API Oriented Device                 save(myView);             }             break;         case android.R.id.home:             this.finish();             break;       }     return super.onOptionsItemSelected(item); }  //Share the Image public void onShareImageItem() {     String package_name = getPackageName();      // Get access to the URI for the bitmap     Uri bmpUri = getLocalBitmapUri(iv);     if (bmpUri != null) {         // Construct a ShareIntent with link to image         Intent shareIntent = new Intent();         shareIntent.setAction(Intent.ACTION_SEND);         shareIntent.putExtra(Intent.EXTRA_STREAM, bmpUri);         shareIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.app_name) + "\n" + "https://play.google.com/store/apps/details?id=" + package_name);          shareIntent.setType("image/*");         startActivity(Intent.createChooser(shareIntent, getString(R.string.action_share)));     } else {     } }  // Returns the URI path to the Bitmap displayed in specified ImageView public Uri getLocalBitmapUri(ImageView iv) {     iv.setImageBitmap(myView.scaledBitmap);     // Extract Bitmap from ImageView drawable     drawable = iv.getDrawable();     Bitmap bmp = null;     if (drawable instanceof BitmapDrawable) {         bmp = ((BitmapDrawable) iv.getDrawable()).getBitmap();     } else {         return null;     }     // Store image to default external storage directory     Uri bmpUri = null;     try {         File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");         FileOutputStream out = new FileOutputStream(file);         bmp.compress(Bitmap.CompressFormat.PNG, 90, out);         out.close();         bmpUri = Uri.fromFile(file);     } catch (IOException e) {         e.printStackTrace();     }     return bmpUri; }  public void save(View view) {     File filename;     iv.setImageBitmap(myView.scaledBitmap);      try {          File filepath = Environment.getExternalStorageDirectory();         File dir = new File(filepath.getAbsolutePath() + "/" + getString(R.string.app_name) + "/");         dir.mkdirs();         String fileName = "/" + System.currentTimeMillis() + "image.jpg";         ;         filename = new File(dir, fileName);         FileOutputStream fos = new FileOutputStream(filename);         myView.scaledBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);         fos.flush();         fos.close();         Toast.makeText(getApplicationContext(), getString(R.string.save), Toast.LENGTH_LONG).show();         MediaScannerConnection.scanFile(MainActivity.this,                 new String[]{filename.toString()}, null,                 new MediaScannerConnection.OnScanCompletedListener() {                     public void onScanCompleted(String path, Uri uri) {                         Log.i("ExternalStorage", "Scanned " + path + ":");                         Log.i("ExternalStorage", "-> uri=" + uri);                     }                 });     } catch (Exception e) {         e.printStackTrace();     } }  @Override public void onClick(View view) {     enable();     switch (view.getId()) {         case R.id.white:             paint.setColor(getResources().getColor(R.color.white));             White.setSelected(true);             break;         case R.id.black:             paint.setColor(getResources().getColor(R.color.black));             Black.setSelected(true);             break;         case R.id.gray:             paint.setColor(getResources().getColor(R.color.gray));             Gray.setSelected(true);             break;         case R.id.light_orange:             paint.setColor(getResources().getColor(R.color.light_orange));             lightOrange.setSelected(true);             break;         case R.id.brown:             paint.setColor(getResources().getColor(R.color.brown));             Brown.setSelected(true);             break;         case R.id.yellow:             paint.setColor(getResources().getColor(R.color.yellow));             Yellow.setSelected(true);             break;         case R.id.deep_blue:             paint.setColor(getResources().getColor(R.color.deep_blue));             deepBlue.setSelected(true);             break;         case R.id.light_blue:             paint.setColor(getResources().getColor(R.color.light_blue));             lightBlue.setSelected(true);             break;         case R.id.deep_purple:             paint.setColor(getResources().getColor(R.color.deep_purple));             deepPurple.setSelected(true);             break;         case R.id.light_purple:             paint.setColor(getResources().getColor(R.color.light_purple));             lightPurple.setSelected(true);             break;         case R.id.deep_green:             paint.setColor(getResources().getColor(R.color.deep_green));             deepGreen.setSelected(true);             break;         case R.id.light_green:             paint.setColor(getResources().getColor(R.color.light_green));             lightGreen.setSelected(true);             break;         case R.id.deep_pink:             paint.setColor(getResources().getColor(R.color.deep_pink));             deepPink.setSelected(true);             break;         case R.id.light_pink:             paint.setColor(getResources().getColor(R.color.light_pink));             lightPink.setSelected(true);             break;         case R.id.red:             paint.setColor(getResources().getColor(R.color.red));             Red.setSelected(true);             break;         case R.id.deep_orange:             paint.setColor(getResources().getColor(R.color.deep_orange));             deepOrange.setSelected(true);             break;     }  }  public void enable() {     White.setSelected(false);     Gray.setSelected(false);     Black.setSelected(false);     lightOrange.setSelected(false);     Brown.setSelected(false);     Yellow.setSelected(false);     deepBlue.setSelected(false);     lightBlue.setSelected(false);     deepPurple.setSelected(false);     lightPurple.setSelected(false);     deepGreen.setSelected(false);     lightGreen.setSelected(false);     deepPink.setSelected(false);     lightPink.setSelected(false);     Red.setSelected(false);     deepOrange.setSelected(false);  }  private boolean checkPermission() {     int result = ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);     if (result == PackageManager.PERMISSION_GRANTED) {         return true;     } else {         return false;     } }  private void requestPermission() {      if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {         Toast.makeText(MainActivity.this, getString(R.string.permission), Toast.LENGTH_LONG).show();     } else {         ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);     } }  @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {     switch (requestCode) {         case PERMISSION_REQUEST_CODE:             if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                 Log.e("value", "Permission Granted, Now you can use local drive .");             } else {                 Log.e("value", "Permission Denied, You cannot use local drive .");             }             break;     } }  private void requestNewInterstitial() {     AdRequest adRequest = new AdRequest.Builder().build();     mInterstitialAd.loadAd(adRequest); }  // flood fill public class MyView extends View {      Point p1 = new Point();     Bitmap mBitmap, scaledBitmap;     ProgressDialog pd;     Canvas canvas;     private Path path;     //Test 20/8/2017//     private ScaleGestureDetector scaleDetector;     private float scaleFactor = 1.f;     //////////////////      public MyView(Context context) {         super(context);         //Test 20/8/2017//         init(context);         //////////////////          this.path = new Path();         paint = new Paint();         paint.setAntiAlias(true);         pd = new ProgressDialog(context);          paint.setStyle(Paint.Style.STROKE);         paint.setStrokeJoin(Paint.Join.ROUND);         paint.setStrokeWidth(5f);         int id = getResources().getIdentifier("gp" + code + "_" + position, "drawable", getPackageName());         mBitmap = BitmapFactory.decodeResource(getResources(),                 id).copy(Bitmap.Config.ARGB_8888, true);         // Get the screen dimension         DisplayMetrics displaymetrics = new DisplayMetrics();         getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);         Display getOrient = getWindowManager().getDefaultDisplay();         int orientation = Configuration.ORIENTATION_UNDEFINED;         if (getOrient.getWidth() == getOrient.getHeight()) {             orientation = Configuration.ORIENTATION_SQUARE;         } else {             if (getOrient.getWidth() < getOrient.getHeight()) {                 orientation = Configuration.ORIENTATION_PORTRAIT;             } else {                 orientation = Configuration.ORIENTATION_LANDSCAPE;             }          }          if (orientation == Configuration.ORIENTATION_PORTRAIT) {              h = displaymetrics.heightPixels / 2 + 100;             w = displaymetrics.widthPixels;         }         if (orientation == Configuration.ORIENTATION_LANDSCAPE) {             //for mdpi screen 760×1024 tablet             Display display = getWindowManager().getDefaultDisplay();             float density = context.getResources().getDisplayMetrics().density;             if (density >= 1.0 && display.getWidth() == 1024) {                 h = displaymetrics.heightPixels - 200;                 w = displaymetrics.widthPixels - 100;             } else {                 h = displaymetrics.heightPixels - 500;                 w = displaymetrics.widthPixels - 700;             }         }         scaledBitmap = Bitmap.createScaledBitmap(mBitmap, w, h, false);      }      //Test 20/8/2017//     public MyView(Context context, AttributeSet attrs) {         super(context, attrs);         init(context);     }      public MyView(Context context, AttributeSet attrs, int defStyle) {         super(context, attrs, defStyle);         init(context);     }      private void init(Context ctx) {         scaleDetector = new ScaleGestureDetector(ctx, new ScaleListener());     }     /////////////////      @Override     protected void onDraw(Canvas canvas) {         this.canvas = canvas;         super.onDraw(canvas);         DisplayMetrics metrics = new DisplayMetrics();         getWindowManager().getDefaultDisplay().getMetrics(metrics);         //Test 20/8/2017//         canvas.scale(this.scaleFactor, this.scaleFactor,    this.scaleDetector.getPreviousSpanX(),this.scaleDetector.getPreviousSpanY());           //////////////////         canvas.drawBitmap(scaledBitmap, 0, 0, paint);         for (Path p : paths) {             canvas.drawPath(p, paint);             canvas.save();          }       }      @Override     public boolean onTouchEvent(MotionEvent event) {         //Test 20/8/2017//         // scaleDetector.onTouchEvent(event);         //////////////////         float x = event.getX();         float y = event.getY();         switch (event.getAction()) {             case MotionEvent.ACTION_UP:                 try {                     p1 = new Point();                     p1.x = (int) x;                     p1.y = (int) y;                     drawnPoints.add(p1);                     final int sourceColor = scaledBitmap.getPixel((int) x,                       (int) y);                     final int targetColor = paint.getColor();                     new TheTask(scaledBitmap, p1, sourceColor,                     targetColor).execute();                     paths.add(path);                     invalidate();                 } catch (Exception e) {                     e.printStackTrace();                 }                 break;             case MotionEvent.ACTION_MOVE:                 scaleDetector.onTouchEvent(event);                 break;           }         return true;     }      public void clear() {         path.reset();         invalidate();     }      public int getCurrentPaintColor() {         return paint.getColor();     }      @Override     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         super.onMeasure(widthMeasureSpec, heightMeasureSpec);          w = widthMeasureSpec - MeasureSpec.EXACTLY;         h = heightMeasureSpec - MeasureSpec.EXACTLY;          Log.d("Dim", Integer.toString(w) + " | " + Integer.toString(h));     }      class TheTask extends AsyncTask<Void, Integer, Void> {          Bitmap bmp;         Point pt;         int replacementColor, targetColor;          public TheTask(Bitmap bm, Point p, int sc, int tc) {             this.bmp = bm;             this.pt = p;             this.replacementColor = tc;             this.targetColor = sc;             pd.show();          }          @Override         protected void onPreExecute() {             pd.show();           }          @Override         protected void onProgressUpdate(Integer... values) {          }          @Override         protected Void doInBackground(Void... params) {             FloodFill f = new FloodFill();             f.floodFill(bmp, pt, targetColor, replacementColor);             return null;         }          @Override         protected void onPostExecute(Void result) {             pd.dismiss();             invalidate();         }     }      private class ScaleListener extends             ScaleGestureDetector.SimpleOnScaleGestureListener {         @Override         public boolean onScale(ScaleGestureDetector detector) {             scaleFactor *= detector.getScaleFactor();             scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 10.0f));             invalidate();             return true;         }     } }   public class FloodFill {     public void floodFill(Bitmap image, Point node, int targetColor,                           int replacementColor) {         int width = image.getWidth();         int height = image.getHeight();         int target = targetColor;         int replacement = replacementColor;         if (target != replacement) {             Queue<Point> queue = new LinkedList<Point>();             do {                  int x = node.x;                 int y = node.y;                 while (x > 0 && image.getPixel(x - 1, y) == target) {                     x--;                  }                 boolean spanUp = false;                 boolean spanDown = false;                 while (x < width && image.getPixel(x, y) == target) {                     image.setPixel(x, y, replacement);                     if (!spanUp && y > 0                             && image.getPixel(x, y - 1) == target) {                         queue.add(new Point(x, y - 1));                         spanUp = true;                     } else if (spanUp && y > 0                             && image.getPixel(x, y - 1) != target) {                         spanUp = false;                     }                     if (!spanDown && y < height - 1                             && image.getPixel(x, y + 1) == target) {                         queue.add(new Point(x, y + 1));                         spanDown = true;                     } else if (spanDown && y < height - 1                             && image.getPixel(x, y + 1) != target) {                         spanDown = false;                     }                     x++;                 }             } while ((node = queue.poll()) != null);         }     } }  } 

So please I need help to resolve the above problems.

Kindly let me know in case you need more details.

Thanks in advance.

Best regards,

Leenah.

0 Answers

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment