Last active
April 27, 2016 14:29
-
-
Save robbiemu/0ad1ae50e0146325c02d to your computer and use it in GitHub Desktop.
a custom view that indicates wind speed and direction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
public class DetailFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { | |
private WindView mWindGraphic; | |
... | |
@Override | |
public View onCreateView(LayoutInflater inflater, ViewGroup container, | |
Bundle savedInstanceState) { | |
... | |
mWindGraphic = (WindView) rootView.findViewById(R.id.detail_wind_graphic); | |
... | |
} | |
... | |
@Override | |
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { | |
... | |
// Read wind speed and direction from cursor and update view | |
float windSpeedStr = data.getFloat(COL_WEATHER_WIND_SPEED); | |
float windDirStr = data.getFloat(COL_WEATHER_DEGREES); | |
mWindView.setText(Utility.getFormattedWind(getActivity(), windSpeedStr, windDirStr)); | |
mWindGraphic.setWindSpeed((int) windSpeedStr); | |
mWindGraphic.setWindOriginDegrees(windDirStr); | |
mWindGraphic.setForegroundColor(getResources().getColor(R.color.sunshine_light_blue)); | |
mWindGraphic.setBackgroundColor(getResources().getColor(R.color.sunshine_dark_blue)); | |
... | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
<com.example.android.sunshine.app.WindView | |
android:id="@+id/detail_wind_graphic" | |
android:layout_marginTop="4dp" | |
android:layout_width="120dp" | |
android:layout_height="120dp" /> | |
... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<vector android:height="24dp" android:viewportHeight="512.0" | |
android:viewportWidth="512.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> | |
<path android:fillColor="#FF000000" android:pathData="M256,17.1c-75.7,0 -137.1,61.4 -137.1,137.1 0.1,23.3 6,46.1 11.6,56.3L256,494.9l120,-274.2h-0.1c11.3,-20.3 17.2,-43.2 17.2,-66.4C393.1,78.5 331.7,17.1 256,17.1zM256,85.7a68.6,68.6 0,0 1,68.6 68.6A68.6,68.6 0,0 1,256 222.8a68.6,68.6 0,0 1,-68.6 -68.6A68.6,68.6 0,0 1,256 85.7z"/> | |
</vector> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<vector xmlns:android="http://schemas.android.com/apk/res/android" | |
android:width="172dp" | |
android:height="172dp" | |
android:viewportWidth="172.0" | |
android:viewportHeight="172.0"> | |
<path | |
android:pathData="M74.29,11.9c-31.98,5 -57.24,30.26 -62.24,62.24l9.09,-2.27c2.64,-12.39 8.78,-23.77 17.95,-32.93c9.17,-9.17 20.55,-15.31 32.93,-17.95L74.29,11.9z" | |
android:fillColor="#231F20"/> | |
<path | |
android:pathData="M97.6,11.9l2.27,9.09c12.39,2.64 23.77,8.78 32.93,17.95c9.16,9.17 15.31,20.55 17.95,32.93l9.09,2.27C154.83,42.17 129.57,16.91 97.6,11.9z" | |
android:fillColor="#231F20"/> | |
<path | |
android:pathData="M72.02,150.6c-12.39,-2.63 -23.77,-8.78 -32.93,-17.95c-9.16,-9.17 -15.31,-20.55 -17.95,-32.93l-9.09,-2.27c5,31.98 30.26,57.24 62.24,62.24L72.02,150.6z" | |
android:fillColor="#231F20"/> | |
<path | |
android:pathData="M150.75,99.72c-2.63,12.39 -8.78,23.77 -17.95,32.93c-9.17,9.17 -20.55,15.31 -32.93,17.95l-2.27,9.09c31.98,-5 57.24,-30.26 62.24,-62.24L150.75,99.72z" | |
android:fillColor="#231F20"/> | |
<path | |
android:pathData="M171.26,85.8L109.62,70.39l16.54,-24.81L101.35,62.12L85.94,0.47L70.53,62.12L45.72,45.58l16.54,24.81L0.62,85.8l61.64,15.41L45.72,126.02l24.81,-16.54l15.41,61.64l15.41,-61.64l24.81,16.54L109.62,101.21L171.26,85.8zM85.94,23.93l10.88,43.52c-3.19,-1.89 -6.91,-2.98 -10.88,-2.98L85.94,23.93zM64.61,85.8L64.61,85.8L24.07,85.8l43.52,-10.88C65.7,78.1 64.61,81.82 64.61,85.8zM85.94,147.66l-10.88,-43.52c3.19,1.89 6.91,2.98 10.88,2.98l0,0L85.94,147.66zM85.94,102.86c-9.41,0 -17.06,-7.66 -17.06,-17.06S76.53,68.73 85.94,68.73c9.41,0 17.07,7.65 17.07,17.06S95.35,102.86 85.94,102.86zM107.27,85.8h40.54l-43.52,10.88C106.18,93.49 107.27,89.77 107.27,85.8z" | |
android:fillColor="#231F20"/> | |
<path | |
android:pathData="M85.94,94.33c-4.7,0 -8.53,-3.83 -8.53,-8.53c0,-4.7 3.83,-8.53 8.53,-8.53s8.53,3.83 8.53,8.53C94.48,90.5 90.65,94.33 85.94,94.33z" | |
android:fillColor="#231F20"/> | |
</vector> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.android.sunshine.app; | |
import android.content.Context; | |
import android.graphics.Bitmap; | |
import android.graphics.Canvas; | |
import android.graphics.Matrix; | |
import android.graphics.Paint; | |
import android.graphics.Rect; | |
import android.graphics.Typeface; | |
import android.graphics.drawable.Drawable; | |
import android.os.Build; | |
import android.support.v4.graphics.drawable.DrawableCompat; | |
import android.util.AttributeSet; | |
import android.util.Log; | |
import android.view.View; | |
/** | |
* Created by RobertoTomás on 0023, 23/3/2016. | |
*/ | |
public class WindView extends View { | |
private static final float GESTURE_THRESHOLD_DIP = 16.0f; | |
private Bitmap pDirectionArrow; | |
private Bitmap pCompassRing; | |
private Drawable pDirectionArrowVector; | |
private Drawable pCompassRingVector; | |
private final Paint pSpeedText = new Paint(Paint.ANTI_ALIAS_FLAG); | |
private final Matrix pMatrix = new Matrix(); | |
private Float pDensity; | |
private Rect pVectorBoundingRectangle; | |
private int mForegroundColor; | |
private int mBackgroundColor; | |
private int mWindSpeed; | |
private float mWindOriginDegrees; | |
public float getWindOriginDegrees() { | |
return mWindOriginDegrees; | |
} | |
public void setWindOriginDegrees(float mWindOriginDegrees) { | |
this.mWindOriginDegrees = mWindOriginDegrees; | |
_rotateArrow(); | |
invalidate(); | |
} | |
public int getForegroundColor() { | |
return mForegroundColor; | |
} | |
/** | |
* The color expected is the resolved color: `getResources().getcolor(R.color...)` | |
* @param foregroundColor | |
*/ | |
public void setForegroundColor(int foregroundColor) { | |
this.mForegroundColor = foregroundColor; | |
_changeForegroundColor(); | |
invalidate(); | |
} | |
private void _changeForegroundColor(){ | |
this.pDirectionArrow = _getBitmap(pDirectionArrowVector, mForegroundColor); | |
} | |
public int getBackgroundColor() { | |
return mBackgroundColor; | |
} | |
/** | |
* The color expected is the resolved color: `getResources().getcolor(R.color...)` | |
* @param backgroundColor | |
*/ | |
public void setBackgroundColor(int backgroundColor) { | |
this.mBackgroundColor = backgroundColor; | |
_changeBackgroundColor(); | |
invalidate(); | |
} | |
private void _changeBackgroundColor(){ | |
this.pCompassRing = _getBitmap(pCompassRingVector, mBackgroundColor); | |
} | |
public int getWindSpeed() { | |
return mWindSpeed; | |
} | |
public void setWindSpeed(int wind_speed) { | |
this.mWindSpeed = wind_speed; | |
invalidate(); | |
} | |
public String getWindSpeedText (){ | |
return Integer.toString(mWindSpeed) + " km/h"; | |
} | |
/** Constructors **/ | |
public WindView(Context c){ | |
super(c); | |
objectHandler(c); | |
} | |
public WindView(Context c, AttributeSet attrs) { | |
super(c, attrs); | |
objectHandler(c); | |
} | |
public WindView(Context c, AttributeSet attrs, int DefaultStyle) { | |
super(c, attrs, DefaultStyle); | |
objectHandler(c); | |
} | |
public void objectHandler(Context c){ | |
this.mForegroundColor = getResources().getColor(R.color.primary_dark_material_light); | |
this.mBackgroundColor = getResources().getColor(R.color.primary_material_dark); | |
this.mWindSpeed = 0; | |
this.mWindOriginDegrees = 0; | |
this.pVectorBoundingRectangle = new Rect (); | |
this.pDensity = getContext().getResources().getDisplayMetrics().density; | |
this.pCompassRingVector = _getVector(R.drawable.svg_wind_compass_ring); | |
this.pDirectionArrowVector = _getVector(R.drawable.svg_wind_arrow); | |
this.pCompassRing = _getBitmap(pCompassRingVector, mBackgroundColor); | |
this.pDirectionArrow = _getBitmap(pDirectionArrowVector, mForegroundColor); | |
pSpeedText.setStyle(Paint.Style.FILL); | |
pSpeedText.setColor(mForegroundColor); | |
pSpeedText.setAntiAlias(true); | |
pSpeedText.setTextAlign(Paint.Align.LEFT); | |
Typeface typeface = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD_ITALIC); | |
pSpeedText.setTypeface(typeface); | |
} | |
private Drawable _getVector(int drawableId) { | |
Drawable vectorDrawable; | |
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP){ | |
vectorDrawable = getResources().getDrawable(drawableId,null); | |
}else { | |
vectorDrawable = getResources().getDrawable(drawableId); | |
} | |
return vectorDrawable; | |
} | |
private Bitmap _getBitmap(Drawable vectorDrawable, int color) { | |
int h = vectorDrawable.getIntrinsicHeight(); | |
int w = vectorDrawable.getIntrinsicWidth(); | |
if(pVectorBoundingRectangle.isEmpty()){ | |
pVectorBoundingRectangle.set(0,0, w, h); | |
} else { | |
h = pVectorBoundingRectangle.height(); | |
w = pVectorBoundingRectangle.width(); | |
//Setting a pixel default if intrinsic height or width is not found , eg a shape drawable | |
h=h>0?h:96; | |
w=w>0?w:96; | |
if ((h != pVectorBoundingRectangle.height()) || (w != pVectorBoundingRectangle.width())) { | |
// the rectangle was not empty, but still had a 0 width or height value | |
pVectorBoundingRectangle.set(0,0, w, h); | |
} | |
} | |
vectorDrawable.setBounds(pVectorBoundingRectangle); | |
// Wrap the drawable so that future tinting calls work | |
// on pre-v21 devices. Always use the returned drawable. | |
Drawable wrapDrawable = DrawableCompat.wrap(vectorDrawable); | |
DrawableCompat.setTint(wrapDrawable.mutate(), color); | |
wrapDrawable.setBounds(pVectorBoundingRectangle); | |
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); | |
Canvas canvas = new Canvas(bm); | |
wrapDrawable.draw(canvas); | |
return bm; | |
} | |
private Matrix _rotateArrow() { | |
// normally we'd want (180+mWindOriginDegrees)%360 for the direction since the wind comes _from_ | |
// the orientation given ina weather report. However our graphic image here has the arrow already | |
// rotated 180 from normal | |
pMatrix.setRotate(mWindOriginDegrees, pDirectionArrow.getWidth() / 2, pDirectionArrow.getHeight() / 2); | |
return pMatrix; | |
} | |
private int _measureWidth(int measureSpec) { | |
int preferred = pCompassRing.getWidth() * 2; | |
return _getMeasurement(measureSpec, preferred); | |
} | |
private int _measureHeight(int measureSpec) { | |
int preferred = pCompassRing.getHeight() * 2; | |
return _getMeasurement(measureSpec, preferred); | |
} | |
private int _getMeasurement(int measureSpec, int preferred) { | |
int specSize = MeasureSpec.getSize(measureSpec); | |
int measurement = 0; | |
switch(MeasureSpec.getMode(measureSpec)) { | |
case MeasureSpec.EXACTLY: | |
// This means the width of this view has been given. | |
measurement = specSize; | |
break; | |
case MeasureSpec.AT_MOST: | |
// Take the minimum of the preferred size and what | |
// we were told to be. | |
measurement = Math.min(preferred, specSize); | |
break; | |
default: | |
measurement = preferred; | |
break; | |
} | |
return measurement; | |
} | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
int renderWidth = _measureWidth(widthMeasureSpec); | |
int renderHeight = _measureHeight(heightMeasureSpec); | |
pVectorBoundingRectangle.set(0, 0, (int) Math.round(renderHeight * 0.75), (int) Math.round(renderWidth*0.75)); | |
int textSize = (int) (GESTURE_THRESHOLD_DIP * pDensity + 0.5f); | |
textSize *= pDensity; | |
textSize /= 4; | |
pSpeedText.setTextSize(textSize); | |
setMeasuredDimension(renderWidth, renderHeight); | |
// Log.d("WindView", "Set a bounding rectangle h:" + renderHeight + " w:" +renderWidth); | |
} | |
@Override | |
protected void onDraw(Canvas canvas) { | |
super.onDraw(canvas); | |
canvas.translate(18 * pDensity, 18 * pDensity); | |
canvas.drawBitmap(pCompassRing, 0, 0, null); | |
canvas.drawBitmap(pDirectionArrow, _rotateArrow(), null); | |
String txt = getWindSpeedText(); | |
canvas.drawText( | |
txt, // Text to draw | |
0,//x | |
0,//y | |
pSpeedText // Paint | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
this is a custom view that indicates wind direction.