Wednesday, June 24, 2015

Custom Progress Bar (Lollipop Style Progress Bar)

This article will be covered basic ways to create the spinning progress bar.

We can able to create the customised progress using the below approach. I tried to use some of the library to achieve  spinning progress bar. But it requires more steps to use their components and license. So I tired to create a custom view with spinning circle. I followed the below steps to create the spinning Progress bar.

1. Create the class which extends the View
public class CustomProgressBar extends View

2. Init the Circle Paint Object and Rect Object
 mCirclePaint = new Paint();
 mCircleRectF = new RectF(mPadding, mPadding,
                this.getLayoutParams().width - mPadding,
                this.getLayoutParams().height - mPadding);

3. Draw the item in the onDraw Method
canvas.drawArc(mCircleRectF, mProgress - 90, mProgress, false,
                mCirclePaint);

4. Redraw the circle by the specific intravels using the Handlers here
 //Run in the loop
            mSpinBarHandler.sendEmptyMessageDelayed(0, 15);
            invalidate();

5. Use the View in the Layout
             android:id="@+id/myprogressbar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

6. Start the progress bar whenever you need
CustomProgressBar mCustomProgressBar = (CustomProgressBar)findViewById(R.id.myprogressbar);
mCustomProgressBar.startSpin();


Full Source

package com.myviews;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

public class CustomProgressBar extends View {

    private int mProgress = 0;

    //Used to increase the speed of the progress bar    private int mStepCount = 4;

    private float mPadding = 15.0f;

    private Paint mCirclePaint;

    private RectF mCircleRectF;

    public CustomProgressBar(Context context) {
        super(context);
    }

    public CustomProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    @Override    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (this.getLayoutParams().width < 0                || this.getLayoutParams().height < 0) {
            this.getLayoutParams().width = this.getLayoutParams().height = 150;
        }
        mCircleRectF = new RectF(mPadding, mPadding,
                this.getLayoutParams().width - mPadding,
                this.getLayoutParams().height - mPadding);
    }

    @Override    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawArc(mCircleRectF, mProgress - 90, mProgress, false,
                mCirclePaint);
    }

    public void initView() {
        mCirclePaint = new Paint();
        mCirclePaint.setColor(Color.RED);
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setStyle(Style.STROKE);
        mCirclePaint.setStrokeWidth(15);
    }

    private Handler mProgressBarHandler = new Handler() {
        @Override        public void handleMessage(Message msg) {
            mProgress += mStepCount;
            if (mProgress > 360) {
                mProgress = 0;
            }
            //Run in the loop            mProgressBarHandler.sendEmptyMessageDelayed(0, 15);
            invalidate();
        }
    };


    /**     * Execute the progress. And this method has to be called.     */    public void startSpin() {
        mProgressBarHandler.sendEmptyMessage(0);
    }

    public void reset() {
        mProgress = 0;
        mProgressBarHandler.removeMessages(0);
    }

    public void stop() {
        mProgressBarHandler.removeMessages(0);
    }

}

IN YOUR LAYOUT
<com.myviews.CustomProgressBar    android:id="@+id/myprogressbar"    android:layout_width="wrap_content"    android:layout_height="wrap_content" />

IN YOUR ACTIVITY
CustomProgressBar mCustomProgressBar = (CustomProgressBar) findViewById(R.id.myprogressbar);
mCustomProgressBar.startSpin();

Monday, June 22, 2015

How to align TextView around an ImageView




We can achieve this by using the android.text.style.LeadingMarginSpan.LeadingMarginSpan2 interface which is available in API 8.

An extended version of LeadingMarginSpan, which allows the implementor to specify the number of lines of the paragraph to which this object is attached that the "first line of paragraph" margin width will be applied to.

There should only be one LeadingMarginSpan2 per paragraph. The leading margin line count affects all LeadingMarginSpans in the paragraph, adjusting the number of lines to which the first line margin is applied.

As with LeadingMarginSpans, LeadingMarginSpan2s should be attached from the beginning to the end of a paragraph.


Reference :: 
http://developer.android.com/reference/android/text/style/LeadingMarginSpan.LeadingMarginSpan2.html



Create Custom Leading Margin
class CustomLeadingMargin implements LeadingMarginSpan2 {
        
        private int marginSpace;
        private int numberOfLines;

        CustomLeadingMargin(int numberOfLines, int marginSpace) {
            this.numberOfLines = numberOfLines;
  this.marginSpace = marginSpace;
        }

        @Override
        public int getLeadingMargin(boolean firstLineFlag) {
        return firstLineFlag ? marginSpace : 0;
        }

        @Override
        public int getLeadingMarginLineCount() {
            return numberOfLines;
        }

        @Override
        public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, 
                int top, int baseline, int bottom, CharSequence text, 
                int start, int end, boolean first, Layout layout) {}
}


Apply in the TextView

//Get the string from the String File
String descText = getString(R.string.description);

Drawable dIcon = getResources().getDrawable(R.drawable.icon);
int leftMargin = dIcon.getIntrinsicWidth() + 5;

ImageView icon = (ImageView) findViewById(R.id.startImage);
icon.setBackgroundDrawable(dIcon);

SpannableString mSpannableString = new SpannableString(descText);
ss.setSpan(new CustomLeadingMargin(3, leftMargin), 0, mSpannableString.length(), 0);

((TextView) findViewById(R.id.message_view)).setText(mSpannableString);


Full Implementation

public class LeadingMarginSampleActivity extends Activity {

    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leading_margin_sample);

        //Get the string from the String File        String descText = "An extended version of LeadingMarginSpan, which allows the implementor to specify the number of lines of the paragraph to which this object is attached that the \"first line of paragraph\" margin width will be applied to.";

        Drawable dIcon = getResources().getDrawable(R.drawable.ic_launcher);
        int leftMargin = dIcon.getIntrinsicWidth() + 5;

        ImageView icon = (ImageView) findViewById(R.id.startImage);
        icon.setBackgroundDrawable(dIcon);

        SpannableString mSpannableString = new SpannableString(descText);
        mSpannableString.setSpan(new CustomLeadingMargin(3, leftMargin), 0, mSpannableString.length(), 0);

        ((TextView) findViewById(R.id.description)).setText(mSpannableString);

    }

    class CustomLeadingMargin implements LeadingMarginSpan.LeadingMarginSpan2 {

        private int numberOfLines;
        private int marginSpace;

        CustomLeadingMargin(int numberOfLines, int marginSpace) {
            this.numberOfLines = numberOfLines;
            this.marginSpace = marginSpace;
        }

        @Override        public int getLeadingMargin(boolean firstLineFlag) {
            return firstLineFlag ? marginSpace : 0;
        }

        @Override        public int getLeadingMarginLineCount() {
            return numberOfLines;
        }

        @Override        public void drawLeadingMargin(Canvas c, Paint p, int x, int dir,
                                      int top, int baseline, int bottom, CharSequence text,
                                      int start, int end, boolean first, Layout layout) {
        }
    }

}

activity_leading_margin_sample.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:padding="5dp">

    <TextView        android:id="@+id/description"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="@string/descText" />

    <ImageView        android:id="@+id/startImage"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@drawable/ic_launcher" />
</RelativeLayout>

Output