How to create fan control dial with android custom view.

Fan control dial example, In this example we create circular UI which represent physical fan dial control.



we use Custom view which extends from View class for draw a circular fan dial control and this custom view also draw text labels and indicator for settings fan speed.

0 means fan is off.
1 means fan is law.
2 means fan is medium.
3 means fan is high. 

When user click on fan dail then we move dial indicator to next position and we also change the fan dial color from Off to On when section is 1-3 for indicating that fan is turn on.  

Step -1       
First we create attribute file under the res/value folder this file is named attrs.xml.
In this attrs.xml file we create custom attribute for our custom fan dial view. 
attrs.xml 
<?xml version="1.0" encoding="utf-8"?>
<resource>
<declare-styleable name="FanDialView">
<attr name="onFanColor" format="reference|color" />
<attr name="offFanColor" format="reference|color" />
</declare-styleable>
</resource>
view raw attrs.xml hosted with ❤ by GitHub

Step - 2
In this step we create FanControlView class which extends View class, we will put all the logic inside this class.
 
FanControlView.java

package com.example.funcontrol.trendyprogrammer
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/*
* Custome view which create multiple-postion "Fan control dial".Each click on view increase fanControl postion
* Initially we set to 4 selection (0 to 3)
*
* 0 = off, 1 = Low, 2 = Medium, 3 = High
*/
public class FanControlView extends View {
private static int SELECTION_TOTAL_COUNT = 4; // Total number of selection we have
private float viewWidth; // Custom view width
private float viewHieght; // Custom view height
private Paint textPaint; // For text in the view
private Paint fanControlPaint; // For fan control dial circle in the view
private float radius; // Radius of the fan control dial
private int activeSelection; // The active selection
//let's have String buffer for fan control dial labels and float for calculateXY result.
private final StringBuffer tempLabels = new StringBuffer(8);
private final float[] tempResult = new float[2];
//The color will be set in attributes.
private int onFanColor; // fan cotrol dial color set in the attribute
private int offFanColor; // fan control dial color set in the attribute
/**
* Single parameter constructor called when this custom view is created from
* java code.
*
* @param context The Context the view is running in,using context this view can
* access the current theme, resources, etc.
*/
public FanControlView(Context context) {
super(context)
initialize(context, null);
}
/**
* This constructor is called when a this view is build from an xml file,
* this supplying attributes that ware specified in the xml file.
*
* @param context The Context the view is running in,using context this view can
* access the current theme, resources, etc.
* @param attrs The attributes of the XML tag that is inflating the view.
*/
public FanControlView(Context context, AttributeSet attrs) {
super(context, attrs)
initialize(context, attrs);
}
/**
* This constructor is called to supply the default style(theme)
*
* @param context The Context the view is running in,using context this view can
* access the current theme, resources, etc.
* @param attrs The Context the view is running in,using context this view can
* access the current theme, resources, etc.
* @param defStyleAttr The default style attribute.
*/
public FanControlView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs);
initialize(context, attrs);
}
/**
* Helper method to initialize variables, this method is called by constructors.
*/
private void initialize(Context context, AttributeSet attrs) {
// we create Paint styles used in drawing here.
// This is for performance optimization , Since the OnDraw() method is called
// for every single screen refresh.
//let's set default On fan color and Off fan color
onFanColor = Color.RED;
offFanColor = Color.GREEN;
// Let's get custome attribute OnFanColor and OffFanColor , if They are available.
if (attrs != null) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs,
R.styleable.FanDialView,
0, 0);
//Let's set the fan on and off colors from the attribute values.
onFanColor = typedArray.getColor(R.styleable.FanDialView_onFanColor, onFanColor)
offFanColr = typedArray.getColor(R.styleable.FanDialView_offFanColor, offFanColor)
// recyle the TypedArray when finished
typedArray.recyle();
}
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(Color.Black)
textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setTextSize(30f);
fanControlPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//Let's set the fanControlPaint color.
fanControlPaint.setColor(offFanColor);
//Current selection (Where the fan control dial inidicator is pointing).
activeSelection = 0;
// Let's set up onClick listener for this view
// when we click on this view this click handler receiver click event
// and we Rotate the between different selection states on each click.
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
// Increase the selection forward to the next available choice.
activeSelection = (activeSelection + 1) % SELECTION_TOTAL_COUNT
// Let's change the fan cotrol dial color to indicate fan is on
// when selection is >= 1
if (activeSelection >= 1) {
fanControlPaint.setColor(onFanColor)
} else {
fanControlPaint.setColor(offFanColor)
}
// call invalide for redraw the view.
invalidate();
}
});
}
/**
* onSizeChanged() method called when the size of this view has changed,
* now if this view is just added to view hierarchy , it is called with the initail
* value of 0. let' we initialize drawing bounds for the custome view in this method.
*
* @param w Current width of this view
* @param h Current height of this view
* @param oldw Initial or old width of this view
* @param oldh Initial or old height of this view
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// we will calculate the radius for fan control dial in this method.
width = w;
height = h;
radius = (float) (Math.min(width, height) / 2 * 0.8);
}
/**
* Draw the view content : an outer Red circle to indicate as the "fan control dial"
* and a smaller black circle to serve as the indicator.
* The postion of the indicator is based on activeSelection.
*
* @param canvas The canvas on which all view will be draw.
*/
@Override
protected void onDraw(Canvas canvas) {
//Let's draw the fan control dial
canvas.drawCircle(width / 2, height / 2, radius, fanControlPaint);
// Let's draw the text lables for fan control dial.
final float lableRadius = radius + 20;
StringBuffer labBuffer = tempLabels;
for (int i = 0; i < SELECTION_TOTAL_COUNT; i++) {
float[] xyPostionData = calculateXYForPostion(i, lableRadius);
float x = xyPostionData[0];
float y = xyPostionData[1];
labBuffer.setLength(0);
labBuffer.append(i);
canvas.drawText(labBuffer, 0, labBuffer.length(), x, y, textPaint);
}
//Let's draw the fan control indicator marker on canvas we have.
final flaot fanMarkerIndicator = radius + 35;
flaot[] xyDataForMarkerIndicator = calculateXYForPostion(activeSelection, fanMarkerIndicator);
flaot x = xyDataForMarkerIndicator[0];
flaot y = xyDataForMarkerIndicator[1];
canvas.drawCircle(x, y, 20, textPaint);
}
/**
* calculate the x and y postion for the text lable and fan indicator,
* this method take radius and position number.
* where the text lable and fan control indicator should draw.
*
* @param postion postion index zero-based.
* @param radius The redius where fan control indicator is to be drawn.
* @return this method return 2 element array, Element 0 is x-coordinate, element 1 is Y-coordinate.
*/
private float[] calculateXYForPostion(final int postion, final float radius) {
flaot[] mResult = tempResult;
Double startingAngle = Math.PI * (9 / 8d);
Double angle = startingAngle + (postion * (Math.PI / 4));
mResult[0] = (float) (redius * Math.cos(angle)) + (width / 2);
mResult[1] = (float) (redius * Math.sin(angle)) + (height / 2);
return mResult;
}
}
  
Step - 3
In 3th Step we create activity_main.xml file under the res/layout.In activity_main.xml we use the 
FanControlView Class which we created in step-2. 

activity_main.xml

<?xml version="1.0" endcoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
>
<AppCompactTextView
android:id="@+id/textViewLable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="Fan controler"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="24dp"
app:layout_constraintTop_toTopof="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<com.example.funcontrol.trendyprogrammer.FunControlView
android:id="@+id/funControlView"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
app:OffFunColor="#ff0000"
app:OnFunColor="#00ff00"
app:layout_constraintTop_toBottomOf="@id/textViewLable"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
</android.support.constraint.ConstraintLayout>
Step -4
In 4th Step we create MainActivity class which extends AppCompactActivity class,
This class is our main activity we uses activity_main.xml file to draw UI.

MainActivity.java
package com.example.funcontrol.trendyprogrammer
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Please Leave your comment and let us know your thoughts.
So we can provide more useful tutorials.

No comments:

Post a Comment