UIPickerView in iOS is an UI element that can be used to make a selection from multiple choices (similar to what a dropdown does for a webpage). In this tutorial, I will show how to create similar view in Android which looks like odometer.
It may be used to display changing numbers / text, for instance in real time dashboard widgets. The behavior is similar to how an odometer in a car animates itself.
Download Sample Code
Have a look on few code snippets,
//activity_main.xml
//Odometer.java
//MainActivity.java
It may be used to display changing numbers / text, for instance in real time dashboard widgets. The behavior is similar to how an odometer in a car animates itself.
- Create Odometer with their properties.
<com.harshalbenake.odometer.views.Odometer
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.harshalbenake.odometer.views.Odometer>
- Add EdgeColor of Odometer
app:np_edgeColor="@android:color/white"
- Add CenterColor of Odometer
app:np_centerColor="@android:color/black"
- Add Reading
Reading is the values that you want to show.
app:np_reading="0000"
- Add Slots
Slots means that how many slots you want to create.
app:np_slots="4"
- Add TextColor
app:np_textColor="@color/white"
- Add TextSize
app:np_textSize="18sp"
- Add custom font from .ttf. Put your .ttf file at assets\fonts. Font will apply everywhere title, content, buttons
app:np_font="@string/lato_regular"
- Those attributes necessary to add reading and slots together in Odometer
app:np_reading="0000"
app:np_slots="4"
Refer the below link for complete sample code:-Download Sample Code
Have a look on few code snippets,
//activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.harshalbenake.odometer.views.Odometer android:id="@+id/odometer" android:layout_width="wrap_content" android:layout_height="wrap_content" app:np_centerColor="@android:color/holo_green_dark" app:np_edgeColor="@android:color/white" app:np_font="@string/lato_regular" android:layout_centerInParent="true" app:np_reading="0000" app:np_slots="4" app:np_textColor="@color/white" app:np_textSize="18sp" /> <TextView android:id="@+id/tvOutPut" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/odometer" android:layout_centerHorizontal="true" android:textColor="@color/black" android:textSize="18sp" /> <Button android:id="@+id/btn_submit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="20dp" android:background="@color/black" android:layout_below="@id/tvOutPut" android:text="Submit" android:textColor="@color/white" android:textStyle="bold"/> </RelativeLayout> |
//Odometer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | package com.harshalbenake.odometer.views; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.GradientDrawable; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; import com.harshalbenake.odometer.R; import java.lang.reflect.Field; public class Odometer extends LinearLayout { private LinearLayout llParent; private int slot; private int odo_text_color; private float textSize; private String read, fontName; private int odo_edge_color; private int odo_center_color; public Odometer(Context context, Builder builder) { super(context); initViews(context, builder); } public Odometer(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initViews(context, attrs); } public Odometer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initViews(context, attrs); } private void initViews(Context context, Builder builder) { setOrientation(HORIZONTAL); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.number_picker, this, true); llParent = (LinearLayout) findViewById(R.id.llParent); createNumberPicker(context, builder); } private void initViews(Context context, AttributeSet attrs) { setOrientation(HORIZONTAL); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.number_picker, this, true); llParent = (LinearLayout) findViewById(R.id.llParent); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.Odometer); try { fontName = typedArray.getString(R.styleable.Odometer_np_font); textSize = typedArray.getDimension(R.styleable.Odometer_np_textSize, spToPx(18f)); odo_text_color = typedArray.getColor(R.styleable.Odometer_np_textColor, ContextCompat.getColor(context, R.color.white)); slot = typedArray.getInt(R.styleable.Odometer_np_slots, 6); read = typedArray.getString(R.styleable.Odometer_np_reading); odo_edge_color = typedArray.getResourceId(R.styleable.Odometer_np_edgeColor, R.color.white); odo_center_color = typedArray.getResourceId(R.styleable.Odometer_np_centerColor, R.color.black); } finally { typedArray.recycle(); } if (TextUtils.isEmpty(fontName)) { fontName = "Lato-Regular.ttf"; } if (TextUtils.isEmpty(read)) { read = "000000"; } if (TextUtils.isEmpty(read) || read.length() != slot) { TextView textView = new TextView(context); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.CENTER; textView.setLayoutParams(lp); textView.setTextColor(ContextCompat.getColor(context, R.color.black)); textView.setText("Invalid Values"); llParent.addView(textView); } else { createDynamicNumberPicker(context); } } private GradientDrawable makeGradientDrawable(GradientDrawable.Orientation orientation, int startColor, int centerColor, int endColor) { int[] colors = new int[]{startColor, centerColor, endColor}; GradientDrawable gd = new GradientDrawable(orientation, colors); gd.setCornerRadius(8); gd.setGradientRadius(90); return gd; } private float spToPx(float sp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()); } private void createDynamicNumberPicker(Context context) { for (int i = 1; i <= slot; i++) { NumberPicker numberPicker = new NumberPicker(context); LayoutParams lp = new LayoutParams(90, LayoutParams.WRAP_CONTENT); lp.setMargins(2, 0, 2, 0); lp.gravity = Gravity.CENTER; numberPicker.setLayoutParams(lp); setDividerColor(numberPicker, Color.TRANSPARENT); setNumberPickerTextColor(numberPicker, odo_text_color, fontName, textSize); if (odo_edge_color!=0 && odo_center_color!=0) { numberPicker.setBackgroundDrawable(makeGradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, ContextCompat.getColor(context, odo_edge_color), ContextCompat.getColor(context, odo_center_color), ContextCompat.getColor(context, odo_edge_color))); } numberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); numberPicker.setId(i - 1); numberPicker.setMinValue(0); numberPicker.setMaxValue(9); numberPicker.setWrapSelectorWheel(true); int read_val = Character.getNumericValue(read.charAt(i - 1)); numberPicker.setValue(read_val); llParent.addView(numberPicker); } } private void createNumberPicker(Context context, Builder builder) { for (int i = 1; i <= builder.slot; i++) { NumberPicker numberPicker = new NumberPicker(context); LayoutParams lp = new LayoutParams(90, LayoutParams.WRAP_CONTENT); lp.setMargins(2, 0, 2, 0); lp.gravity = Gravity.CENTER; numberPicker.setLayoutParams(lp); setDividerColor(numberPicker, Color.TRANSPARENT); setNumberPickerTextColor(numberPicker, builder.odo_text_color, builder.font, spToPx(builder.textSize)); numberPicker.setBackgroundDrawable(makeGradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, builder.odo_edge_color, builder.odo_center_color, builder.odo_edge_color)); numberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); numberPicker.setId(i - 1); numberPicker.setMinValue(0); numberPicker.setMaxValue(9); numberPicker.setWrapSelectorWheel(true); int read_val = Character.getNumericValue(builder.reading.charAt(i - 1)); numberPicker.setValue(read_val); llParent.addView(numberPicker); Log.e("add", "add" + i); } } public void setNumberPickerTextColor(NumberPicker numberPicker, int color, String fontName, float textSize) { final int count = numberPicker.getChildCount(); for (int i = 0; i < count; i++) { View child = numberPicker.getChildAt(i); if (child instanceof EditText) { try { Field selectorWheelPaintField = numberPicker.getClass().getDeclaredField("mSelectorWheelPaint"); selectorWheelPaintField.setAccessible(true); ((Paint) selectorWheelPaintField.get(numberPicker)).setColor(color); if (!TextUtils.isEmpty(fontName)) ((Paint) selectorWheelPaintField.get(numberPicker)).setTypeface(Typeface.createFromAsset(getResources().getAssets(), fontName)); ((Paint) selectorWheelPaintField.get(numberPicker)).setTextSize(textSize); ((EditText) child).setTextColor(color); if (!TextUtils.isEmpty(fontName)) ((EditText) child).setTypeface(Typeface.createFromAsset(getResources().getAssets(), fontName)); ((EditText) child).setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); numberPicker.invalidate(); } catch (NoSuchFieldException e) { Log.w("NumberPickerTextColor", e); } catch (IllegalAccessException e) { Log.w("NumberPickerTextColor", e); } catch (IllegalArgumentException e) { Log.w("NumberPickerTextColor", e); } } } } public void setDividerColor(NumberPicker picker, int color) { Field[] pickerFields = NumberPicker.class.getDeclaredFields(); for (Field pf : pickerFields) { if (pf.getName().equals("mSelectionDivider")) { pf.setAccessible(true); try { ColorDrawable colorDrawable = new ColorDrawable(color); pf.set(picker, colorDrawable); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (Resources.NotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } break; } } } public String getFinalOdometerValue() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < llParent.getChildCount(); i++) { NumberPicker localNumberPicker = (NumberPicker) llParent.getChildAt(i); localNumberPicker.getValue(); stringBuilder.append(localNumberPicker.getValue()); stringBuilder.append(" "); } return stringBuilder.toString(); } public static class Builder { // default values private Context context; private String font = ""; private float textSize = 0; private int odo_text_color = 0; private int odo_edge_color = 0; private int odo_center_color = 0; private int slot; private String reading; public Builder(Context context) { this.context = context; odo_text_color = ContextCompat.getColor(context, R.color.white); odo_edge_color = ContextCompat.getColor(context, R.color.startColor); odo_center_color = ContextCompat.getColor(context, R.color.centerColor); textSize = spToPx(14); slot = 4; reading = "0000"; } public Builder background(int odo_edge_color, int odo_center_color) { this.odo_edge_color = odo_edge_color; this.odo_center_color = odo_center_color; return this; } public Builder textColor(int odo_text_color) { this.odo_text_color = odo_text_color; return this; } public Builder font(String font) { this.font = font; return this; } public Builder textSize(float textSize) { this.textSize = textSize; return this; } public Builder slot(int slot) { this.slot = slot; return this; } public Builder reading(String reading) { this.reading = reading; return this; } public Odometer build() { return new Odometer(context, this); } private float spToPx(float sp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics()); } } } |
//MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package com.harshalbenake.odometer; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import com.harshalbenake.odometer.views.Odometer; public class MainActivity extends AppCompatActivity { private Odometer odometer; private TextView tvOutPut; private Button btn_submit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); odometer = (Odometer) findViewById(R.id.odometer); tvOutPut = (TextView) findViewById(R.id.tvOutPut); btn_submit = (Button) findViewById(R.id.btn_submit); btn_submit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { tvOutPut.setText(odometer.getFinalOdometerValue()); } }); } } |
No comments:
Post a Comment