Android Expandable - Collapsible Image View

Android Expandable - Collapsible Image View

        This post is about how to write an Image View/View which will expand/collapse on click, just like Sliding drawer (Deprecated). To do this, all we need is extend a view, then animate the view on click, expand if it is in closed state or collapse if it is in opened state.

Lets do the coding part:-

1). Extend Image View (I'm calling this view as ImageDrawer).

      public class ImageDrawer extends ImageView {}
 
then write required constructor one for XML, other for creating dynamically.

      public class ImageDrawer extends ImageView {

             public ImageDrawer(Context context, AttributeSet attrs, int defStyle) {
                      super(context, attrs, defStyle);
             }

             public ImageDrawer(Context context, AttributeSet attrs) {
                      this(context, attrs, 0);
             }

             public ImageDrawer(Context context) {
                     this(context, null, 0);
             }

      } 

2). Define Global variables:

        private final static int STATE_CLOSED = 0;
 private final static int STATE_BETWEEN = 1;
 private final static int STATE_OPEN = 2;
 private int mClosedHeight = 50; // DEFAULT_CLOSED_STATE_HEIGHT
 private int mOpenHeight; //OPEN STATE HEIGHT
 private int mState = STATE_CLOSED; //CURRENT STATE
 private DecelerateInterpolator mInterpolator; // INTERPOLATOR FOR ANIMATION

3).Override onMeasure method.
        set measure width as default (as in code 10,13,16 in setMeasuredDimension). Height as closedHeight if it is in closed state, or openHeight it is in opened state, else layout height(as in code 10,13,16 in setMeasuredDimension).
       
         ie, set height as mClosedHeight(defined) during closed state, mOpenHeight during opened state, during intermediate state (which will be set during animation as getLayoutParams.height) as layout height.

Note:  We are using an ImageView, the height of imageView is normally the height of image applied. We set mOpenHeight as either height of image if it is smaller than screen width or screen width if image size is not available(code 4-8).

        @Override
 1.protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 2. int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft()
 3.   - getPaddingRight();
 4. mOpenHeight = MeasureSpec.getSize(heightMeasureSpec);
 5. if (getDrawable() != null) {
 6.        mOpenHeight = mOpenHeight <= getDrawable().getIntrinsicHeight() ? mOpenHeight
 7.     : getDrawable().getIntrinsicHeight();
 8. }
 9. if (mState == STATE_CLOSED)
 10.  setMeasuredDimension(resolveSize(width, widthMeasureSpec),
 11.    resolveSize(mClosedHeight, heightMeasureSpec));
 12. else if (mState == STATE_OPEN)
 13.  setMeasuredDimension(resolveSize(width, widthMeasureSpec),
 14.    resolveSize(mOpenHeight, heightMeasureSpec));
 15. else {
 16.  setMeasuredDimension(resolveSize(width, widthMeasureSpec),
 17.    resolveSize(getLayoutParams().height, heightMeasureSpec));
 18. }
 19.} 
  
4). Write animation for expand and collapse as follows:

        //For expanding when clicked and state is closed state.
 
    private void expand() {
       final int targetHeight = mOpenHeight - mClosedHeight;
       Animation a = new Animation() {
            @Override
            protected void applyTransformation(float interpolatedTime,Transformation t) {
                 if (interpolatedTime > 0) {
                   getLayoutParams().height = interpolatedTime == 1 ?
                                             LayoutParams.WRAP_CONTENT
                                           : (int) mClosedHeight
                                + (int) (targetHeight * interpolatedTime);
                      requestLayout();

                 }
            }
      };
   a.setAnimationListener(new AnimationListener() {

   @Override
   public void onAnimationStart(Animation animation) {
     mState = STATE_BETWEEN;
   }

   @Override
   public void onAnimationRepeat(Animation animation) {
   }

   @Override
   public void onAnimationEnd(Animation animation) {
    mState = STATE_OPEN;
   }
  });
  a.setInterpolator(mInterpolator);
  a.setDuration(1000);
  startAnimation(a);
 } 
 
     //For expanding when clicked and state is closed state.
 
  private void collapse() {
    final int targetHeight = mOpenHeight - mClosedHeight;
    Animation anim = new Animation() {
        @Override
        protected void applyTransformation(float interpolatedTime,Transformation t) {
           if (interpolatedTime == 1) {
              getLayoutParams().height = LayoutParams.WRAP_CONTENT;
           } else {
              int current = mOpenHeight
                   - (int) (targetHeight * interpolatedTime);
              if (current >= mClosedHeight) {
                 getLayoutParams().height = current;
              requestLayout();
              } else {
                 getLayoutParams().height = mClosedHeight;
                 requestLayout();
              }
           }
       }
  };
  anim.setAnimationListener(new AnimationListener() {

   @Override
   public void onAnimationStart(Animation animation) {
    mState = STATE_BETWEEN;
   }

   @Override
   public void onAnimationRepeat(Animation animation) {

   }

   @Override
   public void onAnimationEnd(Animation animation) {
    mState = STATE_CLOSED;
    requestLayout();
   }
  });
  anim.setInterpolator(mInterpolator);
  anim.setDuration(1000);
  startAnimation(anim);
 } 
 
5). Write an onClickListener to handle click events if state is closed state call animation expand(),else if state is opened state call collapse, else do nothing.

  public ImageDrawer(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    mInterpolator = new DecelerateInterpolator();
    this.setOnClickListener(new OnClickListener() {

      @Override
       public void onClick(View v) {
         if (mState == STATE_CLOSED) {
         exapand();
      } else if (mState == STATE_OPEN)
        collapse();
      }
     });
 }
 
 
Thats it...You are done.

You can get the whole code here.

Comments