Paint Undo And Redo Example


DrawActivity 

public class DrawActivity extends Activity {

     private Canvas  mCanvas;
     private Path    mPath;
     private Paint       mPaint;
     private ArrayList<Path> paths = new ArrayList<Path>();
     private ArrayList<Path> undonePaths = new ArrayList<Path>();
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final DrawView drawView = new DrawView(this);
        setContentView(R.layout.activity_main);
     
        FrameLayout frm_layout=(FrameLayout) findViewById(R.id.main_frame);
        frm_layout.addView(drawView);
     
        Button btn_undo=(Button) findViewById(R.id.undo);
        btn_undo.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {            
                drawView.onClickUndo();
            }
        });

        Button btn_redo=(Button) findViewById(R.id.redo);
        btn_redo.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {        
                drawView.onClickRedo();
            }
        });
     
        /*Button color = (Button) findViewById (R.id.color);
        color.setOnClickListener(new OnClickListener() {

public void onClick(View v) {

int _color = R.color.red;
new PickerDialog(v.getContext(),new OnColorChangedListener()  {

         public void colorChanged(int color) {
         mPaint.setColor(color);
          }
      }, mPaint.getColor(), _color).show();

}
});  */    
    }
 
    /// color changed function, getting value from ColorPickerDialog ///

    public void colorChanged(int color) {
    mPaint.setColor(color);
    }
 
    public class DrawView extends View implements OnTouchListener  {
     
     
        public DrawView(Context context)   {    
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);    
            this.setOnTouchListener(this);
         
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setColor(Color.GREEN);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(5);
            mCanvas = new Canvas();
            mPath = new Path();
            paths.add(mPath);      
        }            
     
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        }

        @Override
        protected void onDraw(Canvas canvas) {          
        for (Path p : paths){
        canvas.drawPath(p, mPaint);
        }
        }

        private float mX, mY;
        private static final float TOUCH_TOLERANCE = 4;

        private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        }
         
        private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
        mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
        mX = x;
        mY = y;
        }
        }
         
        private void touch_up() {
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw          
        mPath = new Path();
        paths.add(mPath);
        }

        public void onClickUndo () {
        if (paths.size()>0)  {
        undonePaths.add(paths.remove(paths.size()-1));
        invalidate();
        } else  {
        Log.i("undo", "Undo elsecondition");
        }          
        }

        public void onClickRedo (){
        if (undonePaths.size()>0)  {
        paths.add(undonePaths.remove(undonePaths.size()-1));
        invalidate();
        }
        else  {
        Log.i("undo", "Redo elsecondition");
        }          
        }

        public boolean onTouch(View arg0, MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        touch_start(x, y);
        invalidate();
        break;
        case MotionEvent.ACTION_MOVE:
        touch_move(x, y);
        invalidate();
        break;
        case MotionEvent.ACTION_UP:
        touch_up();
        invalidate();
        break;
        }
        return true;
        }
    }
}

XML


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/linearlayout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#FF4500"
        android:orientation="horizontal" >
     
        <Button
            android:id="@+id/undo"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Undo" />

        <Button
            android:id="@+id/redo"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Redo" />    

      <!--   <Button
            android:id="@+id/color"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Color" /> -->
    </LinearLayout>

    <FrameLayout
        android:id="@+id/main_frame"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_below="@+id/linearlayout" >

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/cat" />
    </FrameLayout>

</RelativeLayout>

Why Ice Cream Sandwich Crashes Your App


The following question has plagued StackOverflow ever since Ice Cream Sandwich's initial release:
My application works fine on devices running Android 2.x, but force closes on devices running HoneyComb (3.x) and Ice Cream Sandwich (4.x). Why does this occur?
This is a great question; after all, newer versions of Android are released with the expectation that old apps will remain compatible with new devices. In my experience, there are a couple reasons why this might occur. Most of the time, however, the reason is simple: you are performing a potentially expensive operation on the UI thread.

What is the UI Thread?


The concept and importance of the application's main UI thread is something every Android developer should understand. Each time an application is launched, the system creates a thread called "main" for the application. The main thread (also known as the "UI thread") is in charge of dispatching events to the appropriate views/widgets and thus is very important. It's also the thread where your application interacts with running components of your application's UI. For instance, if you touch a button on the screen, the UI thread dispatches the touch event to the view, which then sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues this request and then tells the view to redraw itself.
This single-thread model can yield poor performance unless Android applications are implemented properly. Specifically, if the UI thread was in charge of running everything in your entire application, performing long operations such as network access or database queries on the UI thread would block the entire user interface. No event would be able to be dispatched—including drawing and touchscreen events—while the long operation is underway. From the user's perspective, the application will appear to be frozen.

In these situations, instant feedback is vital. Studies show that 0.1 seconds is about the limit for having the user feel that the system is reacting instantaneously. Anything slower than this limit will probably be considered as lag (Miller 1968; Card et al. 1991). While a fraction of a second might not seem harmful, even a tenth of a second can be the difference between a good review and a bad review on the Android Market. Even worse, if the UI thread is blocked for more than about five seconds, the user is presented with the notorious "application not responding" (ANR) dialog and the app is force closed.

Why Android Crashes Your App


The reason why your application crashes on Android versions 3.0 and above, but works fine on Android 2.x is because HoneyComb and Ice Cream Sandwich are much stricter about abuse against the UI Thread. For example, when an Android device running HoneyComb or above detects a network access on the UI thread, a NetworkOnMainThreadException will be thrown:
?
1
2
E/AndroidRuntime(673): java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example/com.example.ExampleActivity}: android.os.NetworkOnMainThreadException
The explanation as to why this occurs is well documented on the Android developer's site:
NetworkOnMainThreadException is thrown when an application attempts to perform a networking operation on its main thread. This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads, but it's heavily discouraged.
Some examples of other operations that ICS and HoneyComb won't allow you to perform on the UI thread are:
  • Opening a Socket connection (i.e. new Socket()).
  • HTTP requests (i.e. HTTPClient and HTTPUrlConnection).
  • Attempting to connect to a remote MySQL database.
  • Downloading a file (i.e. Downloader.downloadFile()).
If you are attempting to perform any of these operations on the UI thread, you must wrap them in a worker thread. The easiest way to do this is to use of an AsyncTask, which allows you to perform asynchronous work on your user interface. An AsyncTask will perform the blocking operations in a worker thread and will publish the results on the UI thread, without requiring you to handle threads and/or handlers yourself.

Conclusion


The reason why I decided to write about this topic is because I have seen it come up on StackOverflow and other forums countless times. The majority of the time the error stems from placing expensive operations directly on the UI thread. To ensure you don't disrupt the user experience, it is very important to execute Socket connections, HTTP requests, file downloads, and other long-term operations on a separate Thread. The easiest way to do this is to wrap your operation in an AsyncTask, which launches a new thread and allows you to perform asynchronous work on your user interface.
As always, let me know if this was helpful by +1-ing the post or leaving a comment below! Feel free to ask questions too... I respond to them quickly. :)

Helpful Links


Here are some helpful links that might help you get started with AsyncTasks.

Android Drag and Drop Images in One place to Another place


ACTIVITY

public class MainActivity extends Activity  {
  int windowwidth;
  int windowheight;  
  ImageView ima1,ima2;

  private android.widget.RelativeLayout.LayoutParams layoutParams ;       

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        windowwidth = getWindowManager().getDefaultDisplay().getWidth();
        windowheight = getWindowManager().getDefaultDisplay().getHeight();

        System.out.println("width" +windowwidth);
        System.out.println("height" +windowheight);          

        ima1 = (ImageView)findViewById(R.id.imageview1);
        ima1.setOnTouchListener(new View.OnTouchListener() {

public boolean onTouch(View v, MotionEvent event) {
      layoutParams = (RelativeLayout.LayoutParams) ima1.getLayoutParams();

        switch(event.getAction())                
           {
             case MotionEvent.ACTION_DOWN:                        
                   break;  

             case MotionEvent.ACTION_MOVE:
                   int x_cord = (int) event.getRawX();
                   int y_cord = (int) event.getRawY();

             System.out.println("value of x" +x_cord);
             System.out.println("value of y" +y_cord);        

                   if (x_cord > windowwidth) {
                       x_cord = windowwidth;
                      }
                   if (y_cord > windowheight) {
                       y_cord = windowheight;
                      }
            layoutParams.leftMargin = x_cord-25;
            layoutParams.topMargin = y_cord-25;        
            ima1.setLayoutParams(layoutParams);
                    break;
              default: break;
             }
              return true;
           }
        });

        ima2 = (ImageView)findViewById(R.id.imageview2);
        ima2.setOnTouchListener(new View.OnTouchListener() {      

    public boolean onTouch(View v, MotionEvent event) {
        layoutParams = (RelativeLayout.LayoutParams) ima2.getLayoutParams();
             switch(event.getActionMasked())
                {
                  case MotionEvent.ACTION_DOWN:
                      break;
                  case MotionEvent.ACTION_MOVE:
                      int x_cord = (int) event.getRawX();
                      int y_cord = (int) event.getRawY();

                      System.out.println("value of x1" +x_cord);
                  System.out.println("value of y1" +y_cord);                          

                       if (x_cord > windowwidth) {
                           x_cord = windowwidth;
                       }
                       if (y_cord > windowheight) {
                           y_cord = windowheight;
                       }
                       layoutParams.leftMargin = x_cord - 25;
                       layoutParams.topMargin = y_cord - 75;
                       ima2.setLayoutParams(layoutParams);
                       break;
                   default: break;
               }
               return true;
           }
       });
      }
  }

XML


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ImageView
        android:id="@+id/imageview1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/ic_launcher" />

    <ImageView
        android:id="@+id/imageview2"
        android:layout_width="100sp"
        android:layout_height="100sp"
        android:src="@drawable/ic_launcher" />

</RelativeLayout>

Color Effect Using Seek bar



public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     
        imageview = (ImageView)findViewById(R.id.iv);
        button1 = (Button) findViewById(R.id.button1);  

        redBar = (SeekBar)findViewById(R.id.redbar);
        greenBar = (SeekBar)findViewById(R.id.greenbar);
        blueBar = (SeekBar)findViewById(R.id.bluebar);
     
        redBar.setOnSeekBarChangeListener(colorBarChangeListener);
        greenBar.setOnSeekBarChangeListener(colorBarChangeListener);
        blueBar.setOnSeekBarChangeListener(colorBarChangeListener);
     
        BitmapDrawable drawable = (BitmapDrawable) imageview.getDrawable();
    bitmap = drawable.getBitmap();

DisplayMetrics metrics = getBaseContext().getResources().getDisplayMetrics();
w = bitmap.getWidth();
    h = bitmap.getHeight();      
 
   button1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Bitmap image = doColorFilter(bitmap,  10,  10,  10);
Log.i("doColorFilter_image", "bitmapimage" +image);
imageview.setImageBitmap(image);

setColorFilter(imageview);
}
});      
      //  setColorFilter(imageview);
    }
 
    public static Bitmap doColorFilter(Bitmap src, double redBar, double greenBar, double blueBar) {
// image size
int width = src.getWidth();
int height = src.getHeight();
// create output bitmap
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
// color information
int A, R, G, B;
int pixel;

// scan through all pixels
for(int x = 0; x < width; ++x) {
for(int y = 0; y < height; ++y) {
// get pixel color
pixel = src.getPixel(x, y);
// apply filtering on each channel R, G, B
A = Color.alpha(pixel);
R = (int)(Color.red(pixel) * redBar);
G = (int)(Color.green(pixel) * greenBar);
B = (int)(Color.blue(pixel) * blueBar);
// set new color pixel to output bitmap
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
// return final image
return bmOut;
}
 
    OnSeekBarChangeListener colorBarChangeListener  = new OnSeekBarChangeListener()  {
   
    @Override
    public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
    setColorFilter(imageview);
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
 
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
 
    }};
 
    private void setColorFilter(ImageView iv){
   
       /*
        * 5x4 matrix for transforming the color+alpha components of a Bitmap.
        * The matrix is stored in a single array, and its treated as follows:
        * [  a, b, c, d, e,
        *    f, g, h, i, j,
        *    k, l, m, n, o,
        *    p, q, r, s, t   ]
        *
        * When applied to a color [r, g, b, a], the resulting color is computed
        * as (after clamping)
        * R' = a*R + b*G + c*B + d*A + e;
        * G' = f*R + g*G + h*B + i*A + j;
        * B' = k*R + l*G + m*B + n*A + o;
        * A' = p*R + q*G + r*B + s*A + t;
        */  
   
     float redValue = ((float)redBar.getProgress())/255;
     float greenValue = ((float)greenBar.getProgress())/255;
     float blueValue = ((float)blueBar.getProgress())/255;
   
     float[] colorMatrix = {    
    redValue, 0,          0,         0, 0,      //red
    0,        greenValue, 0,         0, 0,      //green
    0,        0,          blueValue, 0, 0,      //blue
    0,        0,          0,         1, 0      //alpha  
     };
   
     ColorFilter colorFilter = new ColorMatrixColorFilter(colorMatrix);  
     iv.setColorFilter(colorFilter);

    }
}



Select DateRange UsingRangePicker.

  /* * This Method is for select range from picker. * */ private fun selectDateRangeUsingRangePicker () { pageNumber = 1 val displ...