Monthly Archives: October 2018

Adding Transparent Section to Your View – Android

Adding Transparent Section to Your View – Android

Adding-Transparent-Section-to-Your-View-Android

In today’s lesson, we will create a view which has a transparent section(s). This view can be used in many ways, you can use it as an overlay to other views or in any other way. The idea for this demo is to create a view, which has transparent areas which are in different shapes. By combining many areas together you can give a beautiful look to a view.

For e.g. you can see the following image.

 

Adding-Transparent-Section-to-Your-View-Android

 

In the above image, you can see the background has a beautiful photo of coconut trees & above that we have a layer of custom view. BTW I captured that beautiful photo from my phone. In the custom view, I have used rectangles & circles. One rectangle & one circle set as transparent so it can get the above look it has. You can create your own shapes for transparent areas. You can see the full source code at Github repo TrasparentSectionCard.

Now let’s see the code for the same custom view.

 

/**
  * Copyright (C) 2018 Arun Badole.
  *
  * Custom view, which uses different transparent shapes to create a beautiful view. In this particular rectangles & circles are used.
  *
  * @author arunbadole
  */
  public class TransparentCardView extends View {
   
  private final static String TAG = TransparentCardView;
   
  private int cardTopMargin = 0;
  private int cardWidth = 0;
  private int cardHeight = 0;
  private int cardRadiusInner = 0;
  private int cardRadiusOuter = 0;
  private int stroke = 0;
  private int transparentHeight = 0;
  private float centerX = 0;
  private float centerY = 0;
  private int mainWidth = 0;
  private int mainHeight = 0;
   
  private int cardColor;
   
  //Flag for checking whether view is drawn or not.
  private boolean isDrawn = false;
   
  private OnLayoutListener layoutListener;
   
  public TransparentCardView(Context context) {
  super(context);
  }
   
  public TransparentCardView(Context context, @Nullable AttributeSet attrs) {
  super(context, attrs);
  init(context, attrs);
  }
   
  public TransparentCardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init(context, attrs);
  }
   
  public TransparentCardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
  super(context, attrs, defStyleAttr, defStyleRes);
  init(context, attrs);
  }
   
  private void init(Context context, AttributeSet attrs) {
  Log.i(TAG,init);
  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TransparentCardView);
  cardTopMargin = a.getInt(R.styleable.TransparentCardView_cardTopMargin, cardTopMargin);
  cardWidth = a.getInt(R.styleable.TransparentCardView_cardWidth, cardWidth);
  cardHeight = a.getInt(R.styleable.TransparentCardView_cardHeight, cardHeight);
  cardRadiusInner = a.getInt(R.styleable.TransparentCardView_cardRadiusInner, cardRadiusInner);
  cardRadiusOuter = a.getInt(R.styleable.TransparentCardView_cardRadiusOuter, cardRadiusOuter);
  cardColor = a.getInt(R.styleable.TransparentCardView_cardColor, cardColor);
  a.recycle();
  }
   
  /**
  * Calculates required parameters for TransparentCardView creation
  */
  private void defaultAttributes() {
  Log.i(TAG,defaultAttributes);
  mainWidth = getWidth();
  mainHeight = getHeight();
  cardTopMargin = mainHeight / 10;
  cardWidth = mainWidth (mainWidth / 5);
  cardHeight = mainHeight / 2;
  cardRadiusInner = cardWidth / 6;
  cardRadiusOuter = cardRadiusInner + (cardRadiusInner / 10);
  stroke = (cardRadiusInner / 3);
  transparentHeight = cardRadiusOuter;
  centerX = cardWidth / 2;
  centerY = transparentHeight + (cardRadiusOuter / 6);
  cardColor = R.color.colorPrimary;
  }
   
  @Override
  protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  Log.v(TAG, onDraw : getWidth: + getWidth() + , getHeight: + getHeight());
  if (!isDrawn)
  defaultAttributes();
  isDrawn = true;
  Bitmap bitmap = bitmapDraw();
  if (bitmap != null)
  canvas.drawBitmap(bitmap, getWidth() / 2 cardWidth / 2, cardTopMargin, null);
  }
   
  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  super.onLayout(changed, left, top, right, bottom);
  Log.i(TAG, onLayout);
  defaultAttributes();
   
  if (this.layoutListener != null && !isDrawn)
  this.layoutListener.onLayout();
   
  isDrawn = true;
  }
   
  /**
  * Creates a bitmap with transparent circle & a card with dynamic height.
  *
  * @return
  */
  private Bitmap bitmapDraw() {
  Bitmap bitmap = Bitmap.createBitmap(cardWidth, cardHeight, Bitmap.Config.ARGB_8888);
  bitmap.eraseColor(Color.TRANSPARENT);
   
  Canvas canvasBitmap = new Canvas(bitmap);
  canvasBitmap.drawColor(getResources().getColor(cardColor));
   
  Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  paint.setStyle(Paint.Style.FILL);
  paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
   
  canvasBitmap.drawCircle(centerX, centerY, cardRadiusInner, paint);
   
  RectF outerRectangle = new RectF(0, 0, cardWidth, transparentHeight);
  canvasBitmap.drawRect(outerRectangle, paint);
   
  paint.setColor(getResources().getColor(cardColor));
  paint.setStyle(Paint.Style.STROKE);
  paint.setStrokeWidth(stroke);
  paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
  canvasBitmap.drawCircle(centerX, centerY, cardRadiusOuter, paint);
  return bitmap;
  }
   
  public int getCardTopMargin() {
  return cardTopMargin;
  }
   
  public void setCardTopMargin(int cardTopMargin) {
  this.cardTopMargin = cardTopMargin;
  }
   
  public int getCardWidth() {
  return cardWidth;
  }
   
  public void setCardWidth(int cardWidth) {
  this.cardWidth = cardWidth;
  }
   
  public int getCardHeight() {
  return cardHeight;
  }
   
  public void setCardHeight(int cardHeight) {
  this.cardHeight = cardHeight;
  invalidate();
  }
   
  public int getCardRadiusInner() {
  return cardRadiusInner;
  }
   
  public void setCardRadiusInner(int cardRadiusInner) {
  this.cardRadiusInner = cardRadiusInner;
  }
   
  public int getCardRadiusOuter() {
  return cardRadiusOuter;
  }
   
  public void setCardRadiusOuter(int cardRadiusOuter) {
  this.cardRadiusOuter = cardRadiusOuter;
  }
   
  public int getStroke() {
  return stroke;
  }
   
  public void setStroke(int stroke) {
  this.stroke = stroke;
  }
   
  public int getTransparentHeight() {
  return transparentHeight;
  }
   
  public void setTransparentHeight(int transparentHeight) {
  this.transparentHeight = transparentHeight;
  }
   
  public float getCenterX() {
  return centerX;
  }
   
  public void setCenterX(float centerX) {
  this.centerX = centerX;
  }
   
  public float getCenterY() {
  return centerY;
  }
   
  public void setCenterY(float centerY) {
  this.centerY = centerY;
  }
   
  public int getMainWidth() {
  return mainWidth;
  }
   
  public void setMainWidth(int mainWidth) {
  this.mainWidth = mainWidth;
  }
   
  public int getMainHeight() {
  return mainHeight;
  }
   
  public void setMainHeight(int mainHeight) {
  this.mainHeight = mainHeight;
  }
   
  public boolean isDrawn() {
  return isDrawn;
  }
   
  public void setDrawn(boolean drawn) {
  isDrawn = drawn;
  }
   
   
  public int getCardColor() {
  return cardColor;
  }
   
  public void setCardColor(int cardColor) {
  this.cardColor = cardColor;
  invalidate();
  }
   
  public void setOnLayoutListener(OnLayoutListener layoutListener) {
  this.layoutListener = layoutListener;
  }
   
  /**
  * Listener for notifying view layout is done.
  */
  public interface OnLayoutListener {
  void onLayout();
  }
  }

For this custom view I have extended View class & in its onDraw() method I am creating my own Bitmap & setting it on view’s canvas. The bitmap is created in bitmapDraw() method, which actually has all the important drawing part. To draw the view we need the parameters like width & height of the view, center & radius of the circle to be created, top margin, color etc. For this demo, I have calculated all these parameters in method defaultAttributes(). Which actually takes the parent’s width & height as a base & then calculate other parameters accordingly. For these parameters, I have also created custom attributes. You can use these attributes to pass the values in layout XML or can set dynamically as well. For creating custom attributes one has to create attrs.xml, following is mine.

creating custom attributes

You can use these attributes in layout XML like below.

layout xml

These attribute’s values are extracted in method init(). You can check that, but for this demo, I have used defaultAttributes() method.
Now, let’s look at the important drawing part, which is bitmapDraw()method.

bitmapDraw() Method

It creates a Bitmap by provided width & height values (for this demo the values are calculated in defaultAttributes() method). It occupies a rectangular area with a specified width & height. Next, the important one is to set the erase color to the created bitmap, which actually fills the bitmap’s pixels with the specified color. Then the bitmap object is used for creating a Canvas. This canvas will be used for drawing actual shapes. First, we are filling it with color & then a paint object is created, which is actually used for drawing shapes. In shapes, first, we are drawing a circle on the canvas, which is set as transparent by using.

coding

Then we draw a transparent rectangle using the same paint object. Now, in the same paint object, we are setting color, stroke & Xfermode to draw solid circle shape. Once the bitmap canvas is drawn, we return the created Bitmap object. This bitmap object is used in onDraw() method & drawn on the main View’s canvas. I have also created an interface, which tells when the view’s layout is done. Its callback method notifies the user (Activity) when the view is actually drawn. You can use this for your own use cases, in my cases I needed width & height of the custom view, so the onLayout() method notifies me then I get width & height values.

onLayout() method

This tutorial gives you an idea to create a view with transparent sections. You can create any shape with any size for such views. You can tell your ideas & implementations in the comments.

I hope you learned something useful from here. You can check the full source code at Github repo TrasparentSectionCard.

Happy Coding

A Quick Overview of HTTP Methods

A Quick Overview of HTTP Methods

a quick overview of http methods

HTTP is the language of the web. If you’ve ever been involved in developing or communicating with a web server, chances are that you’ve been using HTTP.

HTTP is a server-client protocol. All communication is initiated by the client, in the form of an HTTP request. On receiving this request, the server sends an HTTP response back to the client.

Here is an excellent overview of HTTP that covers the structure of communication over HTTP— https://www.jmarshall.com/easy/http/

A simple HTTP request to fetch posts from a server could look like this –

GET /posts HTTP/1.1

 

The first part, GET is the HTTP method. The second part/posts are the URI. The third partHTTP/1.1 is the HTTP version.

 

The HTTP method indicates the action we wish to perform, and the URI indicates the resource that we want to perform the operation on.

HTTP-Model

The HTTP specification defines these methods – GET, POST, PUT, HEAD, DELETE, OPTIONS and a few more.

 

GET

GET requests are used to retrieve information about the resource specified by the URI. GET is a safe method — that means a GET request should not result in any changes in the server state. It should not cause creation, updating or deletion of any application data. It should be used only for ‘read-only’ actions.

 

POST

POST requests are used to submit data to the server. POST requests may contain a data payload to be submitted to the server. The action performed by the server is determined by the server code. POST requests may be used to create a new resource or to submit data for processing.

 

PUT

PUT requests are used to save an object at the location specified in the request URI. PUT requests should be idempotent. That means that if two or more identical PUT requests are received and executed, the result should be equivalent to executing such a request only once. 

To draw an analogy, a=5 is an idempotent operation since running it once or multiple times results in the value of a being 5. In contrast, a=a+1 is not an idempotent operation, since the value of changes based on how many times we execute the operation.

 

DELETE

DELETE requests are used to delete the object at the location specified in the request URI. DELETE requests are also idempotent.

 

HEAD

HEAD requests are used to retrieve just the headers that would be present in the response of an equivalent GET call. It could be used simply to check whether or not a resource exists or to retrieve the Content-Length Header before deciding whether or not to download a large file. You could also check the Last-Modified header to see if the file was modified since you last retrieved it. The HEAD method is safe. All safe methods are also idempotent since doing nothing once has the same effect as doing nothing multiple times.


Conclusion:

Not all POST methods need to be unsafe. We had a case where we needed to send a large number of email addresses to the server and respond with a yes or no for each of those addresses. It seemed like a GET request at first, but we discovered that some browsers and proxies limit the length of a GET request. It also started feeling more like the URI pointed to a processing service and not to an object, and that it would be fine to POST a list for processing.

To know more about client-server protocol or want to hire a back-end Developer you can contact RemotePanda.

Cropping Videos In Different Shapes In Android

Cropping Videos In Different Shapes In Android

Just before I start, I want you to check the following shapes.

shapes

Many times in your app you deal with images, you might be showing in a list or on a profile page or anywhere else. Normally the image is in rectangular shape only.

But what if you apply these shapes to a profile picture. That will definitely make your view look good. For examples check the following picture.

different shapes

There are many libraries available to give shapes to your images. For example, the above pic is taken from the library CustomShapeImageView.

But what if I have to take it one step further & apply these shapes on a video. Wouldn’t that be more exciting?

To crop a video in any shape, it can be done in many ways for e.g. you can mask a VideoView with shape(.xml) resource. You can create shapes & apply over your VideoView.
But in my method I am not using any default VideoView, instead, I want to create a custom view that can be used to play a video on it.

So let’s start with my approach. As mentioned I will be creating a custom view, for that, I am extending SurfaceView class.

Here is the code.

coding

As you can see I have extended the class SurfaceView class with all the required constructors. Now that we have created a surface, it’s time to draw on it, for that I am overriding dispatchDraw() method of SurfaceView.

coding

In the above method, I have used a flag inOtherShape for checking whether we need a different shape or not. If set it uses clipPath() method which uses a Path object shapePath, which actually clips the canvas to give a specified shape.

Now let’s move to other methods cropCircle(), cropOval(), cropRect() & setOtherShape(). You can see the crop methods actually initializing the shapePath object & adding shapes like circle, oval & rectangle to the path. These methods take coordinates, radius or width & height parameters for positioning & size of the shape.

The last method setOtherShape() actually updates the flag & uses invalidate(), which actually means redraw the view & in result calls dispatchDraw() method. The dispatchDraw() again checks the flag & clips the canvas in set path.

Now we are done with our surface. It’s time to use it & play our video on it. Following is the layout file, which uses the VideoSurfaceView & some buttons for different shapes. You can find the full source code here.

video surface

Now, let’s create an activity CropVideoActivity.

/**
  * Copyright (C) 2018 Arun Badole.
  * <p>
  * Activity which uses the custom surface view for video to crop in different shapes.
  *
  * @author arunbadole
  */
  public class CropVideoActivity extends AppCompatActivity implements SurfaceHolder.Callback, View.OnClickListener {
  private final static String TAG = CropVideoActivity;
   
  private VideoSurfaceView videoView;
   
  private Button btnCropCircle;
  private Button btnCropOval;
  private Button btnFull;
  private Button btnCropRectangle;
   
  //Parameters for video view.
  private int fullLayoutWidth;
  private int fullLayoutHeight;
  private MediaPlayer player;
   
  private int screenWidth;
  private int screenHeight;
   
  @Override
  protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_crop_video);
  initViews();
  initParameters();
  }
   
  void initViews() {
  videoView = findViewById(R.id.activity_crop_video_surface_view);
  btnCropCircle = findViewById(R.id.activity_crop_video_btn_circle);
  btnCropOval = findViewById(R.id.activity_crop_video_btn_oval);
  btnCropRectangle = findViewById(R.id.activity_crop_video_btn_rectangle);
  btnFull = findViewById(R.id.activity_crop_video_btn_full);
   
  btnCropCircle.setOnClickListener(this);
  btnCropOval.setOnClickListener(this);
  btnFull.setOnClickListener(this);
  btnCropRectangle.setOnClickListener(this);
  }
   
  /**
  * Initialise the parameters used.
  */
  private void initParameters() {
  player = MediaPlayer.create(this, R.raw.bird_l);
  SurfaceHolder holder = videoView.getHolder();
  holder.addCallback(this);
   
  //Getting the screen width & height.
  DisplayMetrics displayMetrics = new DisplayMetrics();
  getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
  screenHeight = displayMetrics.heightPixels;
  screenWidth = displayMetrics.widthPixels;
   
  //Setting the video with proper aspect ratio on full screen width & height.
  int dimenFull[] = Utility.getVideoDimensions(player, screenWidth, screenHeight);
  fullLayoutWidth = dimenFull[0];
  fullLayoutHeight = dimenFull[1];
  setVideoLayout(FULL, fullLayoutWidth, fullLayoutHeight);
  }
   
  /**
  * Change the layout dimensions for video view.
  */
  private void setVideoLayout(Shape shape, int width, int height){
  RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) videoView.getLayoutParams();
  layoutParams.width = width;
  layoutParams.height = height;
   
  boolean inOtherShape = true;
  switch (shape) {
  case CIRCLE:
  //You can change the center coordinates & radius.
  videoView.cropCircle(width / 2, width / 2, width / 2);
  break;
   
  case OVAL:
  videoView.cropOval(0, 0, width, height);
  break;
   
  case RECTANGLE:
  videoView.cropRect(0, 0, width, height);
  break;
   
  case FULL:
  inOtherShape = false;
  break;
  }
  videoView.setOtherShape(inOtherShape);
  videoView.setLayoutParams(layoutParams);
  }
   
  @Override
  public void surfaceCreated(SurfaceHolder surfaceHolder) {
  player.setDisplay(surfaceHolder);
  player.start();
  }
   
  @Override
  public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
   
  }
   
  @Override
  public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
   
  }
   
  private void cropCircle() {
  //croppedWidth & croppedHeight are calculated by the required width & height provided.
  // getVideoDimensions() calculates it by maintaining aspect ratio of the video.
  int dimen[] = Utility.getVideoDimensions(player, screenWidth / 4, screenHeight / 4);
  int croppedWidth = dimen[0];
  int croppedHeight = dimen[1];
  setVideoLayout(CIRCLE, croppedWidth, croppedHeight);
  }
   
  private void cropOval() {
  int dimen[] = Utility.getVideoDimensions(player, screenWidth / 2, screenHeight / 2);
  int croppedWidth = dimen[0];
  int croppedHeight = dimen[1];
  setVideoLayout(OVAL, croppedWidth, croppedHeight);
  }
   
  private void cropRectangle() {
  int dimen[] = Utility.getVideoDimensions(player, screenWidth / 2, screenHeight / 2);
  int croppedWidth = dimen[0];
  int croppedHeight = dimen[1];
  setVideoLayout(RECTANGLE, croppedWidth, croppedHeight);
  }
   
  private void fullVideo() {
  setVideoLayout(FULL, fullLayoutWidth, fullLayoutHeight);
  }
   
  @Override
  public void onClick(View view) {
   
  switch (view.getId()) {
  case R.id.activity_crop_video_btn_circle:
  cropCircle();
  break;
  case R.id.activity_crop_video_btn_oval:
  cropOval();
  break;
  case R.id.activity_crop_video_btn_rectangle:
  cropRectangle();
  break;
  case R.id.activity_crop_video_btn_full:
  fullVideo();
  break;
  }
  }
   
  @Override
  protected void onPause() {
  super.onPause();
  if (player != null && player.isPlaying())
  player.pause();
  }
   
  @Override
  protected void onResume() {
  super.onResume();
  if (player != null && !player.isPlaying())
  player.start();
  }
  }
 

In above activity, you can see I have inflated all the required views & initialized the MediaPlayer object player, which is created by video file placed under raw resource. You can see from VideoSurfaceView object I am getting a SurfaceHolder & adding a callback on that, which makes me implement the following three methods.

video surface view coding

Whenever the surfaceCreated() callback method is called, I take that surfaceHolder object set on player object as display & then starts the player by start() method.
By doing just this much you will be able to play the video on your custom VideoSurfaceView & also you can use methods cropCircle(), cropOval(), cropRect() & setOtherShape() to give shapes to video.

Although you have done enough to crop a video in a specified shape. But there may be one issue in that, the videos full or cropped may not maintain the aspect ratio of your video. The video may look creepy, which of course you don’t want. To solve that issue other parameters are used.

layout coding

fullLayoutWidth & fullLayoutHeight, these will be the dimensions of the video in full size, which will maintain the aspect ratio of the video. To maintain the aspect ratio on the device of any size, I first get the width & height of the device’s screen, which is screenWidth & screenHeight respectively. I am using the following method to calculate the width & height which will maintain the aspect ratio of the video.

video dimension coding

In this method, I pass the MediaPlayer object, width & height for which you want to calculate the dimensions which will maintain the aspect ratio.

Initially, I used this method for full screen & calculates the fullLayoutWidth & fullLayoutHeight. Once calculated, I call setVideoLayout() method, by passing values FULL, fullLayoutWidth & fullLayoutHeight. The method resets the LayoutParams of VideoSurfaceView object along with the shape parameters.
It checks Shape enum, calls the crop shape method accordingly & setOtherShape() to draw view in a specified shape.

The following methods calls the setVideoLayout() method but with different shapes & parameters. Here I am using screenWidth & screenHeight for creating shapes, you can pass your own values there.

set video layout

You can change any parameters like center coordinates & radius for circle shape or left, top positions for other shapes.

In my case, the results look like below images.

video in shape

You can also update the VideoSurfaceView class to create more shapes. You can find the full source code at VideoInShape.

I hope you like this & you learned something useful from here.

Happy Coding