Android 视图中的复杂画布查看滚动条
下面是我们用来绘制天气图的代码,它显示为recyclerview中的视图。接近此视图时,列表滚动在绘制画布时向下移动 有人能提出一个解决问题的办法吗?也许是一种在背景中画画的方法,还是一种更好的画法Android 视图中的复杂画布查看滚动条,android,canvas,android-recyclerview,Android,Canvas,Android Recyclerview,下面是我们用来绘制天气图的代码,它显示为recyclerview中的视图。接近此视图时,列表滚动在绘制画布时向下移动 有人能提出一个解决问题的办法吗?也许是一种在背景中画画的方法,还是一种更好的画法 public class WeatherHourlyForecastGraphView extends View { private static String LOG_TAG = WeatherHourlyForecastGraphView.class.getSimpleName();
public class WeatherHourlyForecastGraphView extends View {
private static String LOG_TAG = WeatherHourlyForecastGraphView.class.getSimpleName();
private static int TEMPERATURE = 0;
private static int PRECIPITATION = 1;
private static final String TIME_FORMAT = "h a";
// public static final int GRAPH_HEIGHT_PHONE = 145;
// public static final int GRAPH_HEIGHT_TABLET = 188;
public static final int GRAPH_TOP = (DeviceInfo.isDeviceAPhone() ? 145 : 186);
public static final int GRAPH_DISPLAY_HEIGHT = GRAPH_TOP - 9; // 100 will be displayed at GRAPH_DISPLAY_HEIGHT
private Rect mTextBounds;
// Handle hour in graph being tapped
public interface OnHourSelectionListener {
void onHourSelected(int selectedPosition);
}
// Temperature and precipitation values
private ArrayList<Double> mPrecipitationValues = new ArrayList<>();
private ArrayList<Double> mTemperatureValues = new ArrayList<>();
// Current city for weather - retrieve hourly for this city
private City mCurrentCityWeather;
// Icons
private HashMap<String, Bitmap> mWeatherConditionIcons = new HashMap<>();
private Bitmap mPrecipitationIcon;
// Paint
private Paint mTemperaturePaint;
private Paint mPrecipitationPaint;
private Paint mPrecipitationLinePaint;
private Paint mGraphPaperLinePaint;
private Paint mDotPaint;
private Paint mWhitePaint;
private Paint mTimeTextPaint;
private Paint mTemperatureTextPaint;
private Paint mPrecipitationTextPaint;
private Paint mSelectedPaint;
// When hour is selected. Redraw graph, update conditions
private int mSelectedPosition;
private OnHourSelectionListener mOnHourSelectionListener;
private GestureDetector.SimpleOnGestureListener gestureListener = new GestureListener();
private final GestureDetector gestureDetector = new GestureDetector(getContext(), gestureListener);
// Width (x -values) for displaying single hour in graph
private int mHalfHourlyDisplayWidth;
private int mHourlyDisplayWidth;
private int timeTopPadding;
private int iconTopPadding;
private int tempTopPadding;
private int precipTopPadding;
private int mGraphHeightWithPadding;
private int mContentHeight;
private RectF mIconRectF;
private int numHours = 24;
private Paint backgroundPaint;
private Path tempGeneratePath;
private MyNews myNews;
ArrayList<Double> pathValues;
public WeatherHourlyForecastGraphView(Context context) {
super(context);
}
public WeatherHourlyForecastGraphView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WeatherHourlyForecastGraphView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public WeatherHourlyForecastGraphView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
{
mIconRectF = new RectF();
backgroundPaint = new Paint();
tempGeneratePath = new Path();
myNews = MyNews.getMyNews();
pathValues = new ArrayList<>();
initializePaintsInUse();
initializeDimensions();
mPrecipitationIcon = BitmapFactory.decodeResource(getResources(), R.drawable.rain_drop);
mTextBounds = new Rect(); // Used to calculate the text bounds while drawing. Initialize in constructor to avoid creating object in onDraw()
// setLayerType(LAYER_TYPE_SOFTWARE, null);
}
private void initializePaintsInUse() {
mTemperaturePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTemperaturePaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_temperature_color));
mTemperaturePaint.setStrokeWidth(3);
mTemperaturePaint.setStyle(Paint.Style.STROKE);
mPrecipitationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPrecipitationPaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_precip_color));
mPrecipitationPaint.setStrokeWidth(3);
mPrecipitationLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPrecipitationLinePaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_precip_line_color));
mPrecipitationLinePaint.setStrokeWidth(3);
mPrecipitationLinePaint.setStyle(Paint.Style.STROKE);
mGraphPaperLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mGraphPaperLinePaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_paper_line_color));
mGraphPaperLinePaint.setStrokeWidth(1);
mGraphPaperLinePaint.setPathEffect(null);
mGraphPaperLinePaint.setStyle(Paint.Style.STROKE);
mWhitePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mWhitePaint.setColor(Color.WHITE);
mWhitePaint.setStrokeWidth(DeviceInfo.getValuesInPixel(1));
mSelectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mSelectedPaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_selected_item_color));
mSelectedPaint.setStrokeWidth(2);
mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mDotPaint.setColor(ContextCompat.getColor(getContext(), R.color.pale_blue));
mDotPaint.setStrokeWidth(2);
mTimeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTimeTextPaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_time_text_color));
mTimeTextPaint.setTextSize(getResources().getDimension(R.dimen.hourly_forecast_graph_time_text_size));
mTimeTextPaint.setTypeface(FontManager.getInstance().get(getResources().getString(R.string.roboto_medium_font), Typeface.NORMAL));
mTemperatureTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTemperatureTextPaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_temperature_text_color));
mTemperatureTextPaint.setTextSize(getResources().getDimension(R.dimen.hourly_forecast_graph_temperature_text_size));
mTemperatureTextPaint.setTypeface(DeviceInfo.isDeviceAPhone() ? Typeface.create(getResources().getString(R.string.roboto), Typeface.NORMAL)
: FontManager.getInstance().get(getResources().getString(R.string.roboto_medium_font), Typeface.NORMAL));
mPrecipitationTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPrecipitationTextPaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_temperature_precipitation_color));
mPrecipitationTextPaint.setTextSize(getResources().getDimension(R.dimen.hourly_forecast_graph_precipitation_text_size));
mPrecipitationTextPaint.setTypeface(Typeface.create(getResources().getString(R.string.roboto), Typeface.NORMAL)); // was roboto light
}
private void initializeDimensions() {
// Width when displaying weather for single hour
mHourlyDisplayWidth = DeviceInfo.getValuesInPixel(DeviceInfo.isDeviceAPhone() ? 65 : 101); // was 55, 85
mHalfHourlyDisplayWidth = mHourlyDisplayWidth / 2;
// mGraphHeightWithPadding = DeviceInfo.getValuesInPixel(DeviceInfo.isDeviceAPhone() ? 145 : 188);
mGraphHeightWithPadding = DeviceInfo.getValuesInPixel(GRAPH_TOP);
mContentHeight = (int) getResources().getDimension(R.dimen.hourly_forecast_content_height);
timeTopPadding = (int) getResources().getDimension(R.dimen.hourly_forecast_content_time_top_padding);
iconTopPadding = (int) getResources().getDimension(R.dimen.hourly_forecast_content_icon_top_padding);
tempTopPadding = (int) getResources().getDimension(R.dimen.hourly_forecast_content_temperature_top_padding);
precipTopPadding = (int) getResources().getDimension(R.dimen.hourly_forecast_content_precipitation_top_padding);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(MeasureSpec.getSize(numHours * mHourlyDisplayWidth), MeasureSpec.getSize(mGraphHeightWithPadding + mContentHeight));
}
/**
* This view's onDraw method
* Uses 2 bitmaps to paint each half of graph (Hardware LayerType supports only particular length)
* That avoids issue of path disappearing
* See issues related to canvas rescaling here: https://developer.android.com/guide/topics/graphics/hardware-accel.html
*
* @param canvas the canvas to draw
*/
@Override
protected void onDraw(Canvas canvas) {
// FIXME: Move object allocations out of onDraw(). Also look for object allocations in the methods called by onDraw() as well
// Create left bitmap
Bitmap bitmapLeft = Bitmap.createBitmap(numHours / 2 * mHourlyDisplayWidth, canvas.getHeight(), Bitmap.Config.ARGB_8888);
bitmapLeft.setDensity(DisplayMetrics.DENSITY_DEFAULT);
Canvas bitmapCanvasLeft = new Canvas(bitmapLeft);
bitmapCanvasLeft.drawColor(Color.WHITE);
drawGraphBackground(bitmapCanvasLeft);
// Create right bitmap
Bitmap bitmapRight = Bitmap.createBitmap(numHours / 2 * mHourlyDisplayWidth, canvas.getHeight(), Bitmap.Config.ARGB_8888);
bitmapLeft.setDensity(DisplayMetrics.DENSITY_DEFAULT);
Canvas bitmapCanvasRight = new Canvas(bitmapRight);
bitmapCanvasRight.drawColor(Color.WHITE);
drawGraphBackground(bitmapCanvasRight);
// Draw Temperature graph into each bitmap
drawTemperatureGraph(bitmapCanvasLeft, 0); // always call left side first
drawTemperatureGraph(bitmapCanvasRight, 12);
// Draw Precipitation graph into each bitmap
drawPrecipitationGraph(bitmapCanvasLeft, 0); // always call left side first
drawPrecipitationGraph(bitmapCanvasRight, 12);
// Draw bitmaps into canvas
canvas.drawBitmap(bitmapLeft, 0f, 0f, null);
canvas.drawBitmap(bitmapRight, numHours / 2 * mHourlyDisplayWidth, 0f, null);
// Highlight selected hour
drawSelectedHour(canvas);
// Draw Graph lines
drawGraphLines(canvas);
// Draw text under graph
drawText(canvas);
}
/**
* Draw background including top/bottom colors and graph lines
*
* @param canvas the canvas to draw
*/
private void drawGraphBackground(Canvas canvas) {
backgroundPaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_background_color));
canvas.drawRect(0, 0, canvas.getWidth(), mGraphHeightWithPadding, backgroundPaint);
}
private void drawTemperatureGraph(Canvas canvas, int start) {
Path temperaturePath = generatePath(TEMPERATURE, start);
canvas.drawPath(temperaturePath, mTemperaturePaint);
}
private void drawPrecipitationGraph(Canvas canvas, int start) {
Path precipPath = generatePath(PRECIPITATION, start);
// draw filled
canvas.drawPath(precipPath, mPrecipitationPaint);
// draw line around all
canvas.drawPath(precipPath, mPrecipitationLinePaint);
// hide bottom line
canvas.drawLine(-5, mGraphHeightWithPadding, numHours * mHourlyDisplayWidth, mGraphHeightWithPadding, mPrecipitationPaint);
}
/**
* Given a Temperature or Precipitation value to display, return Y value on graph
*
* @param valueToDisplay the graph value to be displayed
* @return the y position on the graph
*/
private float getGraphHeightForValue(double valueToDisplay) {
// float topGraphValue = (float) (DeviceInfo.isDeviceAPhone() ? 145 * pixelHeight : 186 * pixelHeight); // handle -2 to 112, Temperature 0 is displayed 2 above bottom of graph
// float displayHeight = (float) (DeviceInfo.isDeviceAPhone() ? 140 * pixelHeight: 181 * pixelHeight); // handle -2 to 112, Temperature 0 is displayed 2 above bottom of graph
float topGraphValue = DeviceInfo.getValuesInPixel(GRAPH_TOP); // handle -2 to 112, Temperature 0 is displayed 2 above bottom of graph
float displayHeight = DeviceInfo.getValuesInPixel(GRAPH_DISPLAY_HEIGHT); // handle -2 to 112, Temperature 0 is displayed 2 above bottom of graph
float ratio = (float) (valueToDisplay / 100); // 78 degrees = 78%, 103 degrees = 103%
float y = ratio * displayHeight; // number of pixes out of 107);
return topGraphValue - y;
}
/**
* The selected hour is displayed as rectangle, vertical line through selected value, and circle around hour
*
* @param canvas the canvas to draw
*/
private void drawSelectedHour(Canvas canvas) {
// double selectedTemperature = mTemperatureValues.get(mSelectedPosition);
float selectedX = mSelectedPosition * mHourlyDisplayWidth + mHalfHourlyDisplayWidth;
// Draw line on graph
mTemperaturePaint.setStrokeWidth(1);
canvas.drawLine(selectedX, 0, selectedX, mGraphHeightWithPadding, mTemperaturePaint);
mTemperaturePaint.setStrokeWidth(3);
// Draw Rectangle on graph and text
mSelectedPaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_selected_item_color));
// canvas.drawRect(selectedX-mHalfHourlyDisplayWidth, 0, selectedX+mHalfHourlyDisplayWidth, mGraphHeightWithPadding, mSelectedPaint );
canvas.drawRect(selectedX - mHalfHourlyDisplayWidth, 0, selectedX + mHalfHourlyDisplayWidth, canvas.getHeight(), mSelectedPaint);
// Draw Circles
drawSelectedCircles(canvas);
}
private void drawGraphLines(Canvas canvas) {
// draw horizontal lines at 0, 25,75, 100
for (double i = 0; i <= 100; i += 25) {
canvas.drawLine(0, getGraphHeightForValue(i), canvas.getWidth(), getGraphHeightForValue(i), mGraphPaperLinePaint);
}
// draw vertical lines in center of each hour unit
for (int index = 0; index < numHours; index++) {
float selectedX = index * mHourlyDisplayWidth;
// float selectedX = index * mHourlyDisplayWidth + mHalfHourlyDisplayWidth;
canvas.drawLine(selectedX, 0, selectedX, canvas.getHeight(), mGraphPaperLinePaint);
}
// redraw circles over graph lines
drawSelectedCircles(canvas);
}
private void drawSelectedCircles(Canvas canvas) {
double selectedTemperature = mTemperatureValues.get(mSelectedPosition);
float selectedX = mSelectedPosition * mHourlyDisplayWidth + mHalfHourlyDisplayWidth;
float selectedY = getGraphHeightForValue(selectedTemperature);
mDotPaint.setColor(ContextCompat.getColor(getContext(), R.color.hourly_forecast_graph_temperature_color));
canvas.drawCircle(selectedX, selectedY, getResources().getDimension(R.dimen.hourly_forecast_graph_selected_outer_circle_radius), mDotPaint);
canvas.drawCircle(selectedX, selectedY, getResources().getDimension(R.dimen.hourly_forecast_graph_selected_middle_circle_radius), mWhitePaint);
canvas.drawCircle(selectedX, selectedY, getResources().getDimension(R.dimen.hourly_forecast_graph_selected_inner_circle_radius), mDotPaint);
}
private void drawText(Canvas canvas) {
int xAxisValue = mHalfHourlyDisplayWidth;
float width, height;
Bitmap bitmap;
for (Hour hour : mCurrentCityWeather.hourlyForecast) {
String value = hour.getLocalTime(TIME_FORMAT);
// Draw Time Value
width = mTimeTextPaint.measureText(value);
height = mGraphHeightWithPadding + timeTopPadding + mTimeTextPaint.getTextSize();
canvas.drawText(value, (xAxisValue - (width / 2)), height, mTimeTextPaint);
// Draw Weather Conditions Icon
bitmap = mWeatherConditionIcons.get(myNews.getGlobal().manifest.appBaseUrls.getWeatherConditionIconUrl(hour.iconCode));
height += iconTopPadding;
if (bitmap != null) {
// Set width to 24 for handheld and large. 30 for extra large
width = DeviceInfo.getValuesInPixel(24);
if (DeviceInfo.isDeviceATablet()) {
String screenSize = DeviceInfo.getScreenType();
if (screenSize.equalsIgnoreCase("xlarge")) {
width = DeviceInfo.getValuesInPixel(30);
}
}
// width = DeviceInfo.getValuesInPixel(DeviceInfo.isDeviceAPhone() ? 24 : 30);
// mIconRectF.set((xAxisValue - (width / 2)), height, (xAxisValue + (width / 2)), height + DeviceInfo.getValuesInPixel(DeviceInfo.isDeviceAPhone() ? 24 : 30));
mIconRectF.set((xAxisValue - (width / 2)), height, (xAxisValue + (width / 2)), height + width);
canvas.drawBitmap(bitmap, null, mIconRectF, null);
}
// height += DeviceInfo.getValuesInPixel(24);
height += width;
value = StringUtils.appendDegree(hour.getTemperature());
// Draw Temperature value
width = mTemperatureTextPaint.measureText(value);
height += tempTopPadding + mPrecipitationTextPaint.getTextSize();
canvas.drawText(value, xAxisValue - (width / 2), height, mTemperatureTextPaint);
value = hour.getRainFallInInt() + "%"; // 10% for example
int iconWidth = mPrecipitationIcon.getScaledWidth(canvas) + DeviceInfo.getValuesInPixel(2);
// int iconWidth = DeviceInfo.getValuesInPixel(DeviceInfo.isDeviceAPhone() ? 12 : 18);
width = iconWidth + mPrecipitationTextPaint.measureText(value);
height += precipTopPadding;
// No need to use the rectangle method here because the image is already in perfect size
canvas.drawBitmap(mPrecipitationIcon, (xAxisValue - (width / 2)), height, null);
mPrecipitationTextPaint.getTextBounds(value, 0, value.length(), mTextBounds);
height += (mPrecipitationIcon.getScaledHeight(canvas) - mTextBounds.height()) / 2 + mTextBounds.height();
canvas.drawText(value, (xAxisValue - (width / 2) + iconWidth), height, mPrecipitationTextPaint);
xAxisValue += mHourlyDisplayWidth;
}
}
private Path generatePath(int type, int startIndex) {
pathValues.clear();
tempGeneratePath.reset();
if (type == TEMPERATURE) {
pathValues.addAll(mTemperatureValues);
} else if (type == PRECIPITATION) {
pathValues.addAll(mPrecipitationValues);
}
tempGeneratePath.setFillType(Path.FillType.EVEN_ODD);
float x = mHalfHourlyDisplayWidth;
float y = getGraphHeightForValue(pathValues.get(startIndex));
float x1 = mHourlyDisplayWidth + mHalfHourlyDisplayWidth; //1
float y1 = getGraphHeightForValue(pathValues.get(startIndex + 1));
float xControlPoint = (x + x1) / 2;
float yControlPoint = (y + y1) / 2;
if (startIndex == 0) {
tempGeneratePath.moveTo(-1, y); // start on edge of graph
// path.moveTo(0, y); // start on edge of graph
} else {
float lastY = getGraphHeightForValue(pathValues.get(pathValues.size() / 2 - 1)); // last point on left graph
tempGeneratePath.moveTo(0, lastY); // start at height of last value in left hand graph
}
tempGeneratePath.lineTo(x, y);
tempGeneratePath.quadTo(xControlPoint, yControlPoint, x1, y1);
for (int index = 1; index < pathValues.size() / 2 - 1; index++) {
x = mHourlyDisplayWidth * index + mHalfHourlyDisplayWidth; // current point
y = getGraphHeightForValue(pathValues.get(index + startIndex)); // use start to get proper valye
x1 = mHourlyDisplayWidth * (index + 1) + mHalfHourlyDisplayWidth; // next point
y1 = getGraphHeightForValue(pathValues.get(index + startIndex + 1));
xControlPoint = (x + x1) / 2; // control point
yControlPoint = (y + y1) / 2;
tempGeneratePath.quadTo(xControlPoint, yControlPoint, x1, y1);
}
// By going outside of viewable area, we can fill the precipitation path and draw a line on top
tempGeneratePath.lineTo(x1 + mHourlyDisplayWidth, y1); // add line at end, that goes past viewable area on left graph
tempGeneratePath.lineTo(x1 + mHourlyDisplayWidth, mGraphHeightWithPadding); // below viewable area
tempGeneratePath.lineTo(-5, mGraphHeightWithPadding); //below viewable area, to left of viewable area
tempGeneratePath.close();
return tempGeneratePath;
}
/**
* Called in WeatherAdapter
*
* @param currentCityWeather the weather data
* @param onHourSelectionListener the listener to invoke when an hour is selected on the hourly forecast graph
*/
public void setCurrentCityWeather(City currentCityWeather, OnHourSelectionListener onHourSelectionListener) {
if (currentCityWeather == null) {
return;
}
mCurrentCityWeather = currentCityWeather;
mOnHourSelectionListener = onHourSelectionListener;
mSelectedPosition = 0;
ArrayList<Double> temperatureArray = new ArrayList<>();
ArrayList<Double> precipitationArray = new ArrayList<>();
if (currentCityWeather.hourlyForecast != null) {
for (Hour hour : currentCityWeather.hourlyForecast) {
if (hour != null) {
String weatherConditionIconUrl = myNews.getGlobal().manifest.appBaseUrls.getWeatherConditionIconUrl(hour.iconCode);
myNews.getVolleyHelper().getImageLoader().get(weatherConditionIconUrl, new ImageLoader.ImageListener() {
@Override
public void onResponse(ImageLoader.ImageContainer imageContainer, boolean b) {
mWeatherConditionIcons.put(imageContainer.getRequestUrl(), imageContainer.getBitmap());
invalidate(); // Find a better way to draw these images. Do not invalidate the entire view all times
}
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
temperatureArray.add(hour.getTemperatureInDouble());
precipitationArray.add(hour.getRainFallInDouble());
} else {
temperatureArray.add(0.0);
precipitationArray.add(0.0);
}
}
}
// Set Values
setTemperatureValues(temperatureArray);
setPrecipitationValues(precipitationArray);
// Redraw the view
requestLayout();
invalidate();
}
private void setTemperatureValues(ArrayList<Double> temperatureArray) {
mTemperatureValues.clear();
mTemperatureValues.addAll(temperatureArray);
}
private void setPrecipitationValues(ArrayList<Double> precipitationArray) {
mPrecipitationValues.clear();
mPrecipitationValues.addAll(precipitationArray);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event);
}
/**
* notifySelectionListener
* User has selected an hour in the graph
*
* @param x the x position of the tap event
* @param y the y position of the tap event
* @return {@code true} if the selection is valid, {@code false} otherwise
*/
private boolean notifySelectionListener(float x, float y) {
return determineSelectedHour(x, y);
}
/**
* determineSelectedHour
* Based on coordinates on graph, determine the hour selected
*
* @param x the x position of the tap event
* @param y the y position of the tap event
* @return {@code true} if the selection is valid, {@code false} otherwise
*/
private boolean determineSelectedHour(float x, float y) {
// x is what matters
// hour will be 0 to 23
float graphWidth = numHours * mHourlyDisplayWidth;
float selectedXProportion = x / graphWidth;
float selectedHour = selectedXProportion * numHours;
int selectHourInt = (int) selectedHour;
if (0 <= selectedHour && selectedHour < numHours) {
mSelectedPosition = selectHourInt;
if (mOnHourSelectionListener != null) {
mOnHourSelectionListener.onHourSelected(mSelectedPosition);
myNews.getOmnitureHelper().sendClickAction(OmnitureConstants.FORECAST_LANDING_HOURLY_FORECAST_SWIPE_ACTION,
OmnitureConstants.FORECAST_LANDING_MODULE);
}
invalidate(); // this is what causes the redraw
return true;
}
return false;
}
class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent event) {
return notifySelectionListener(event.getX(), event.getY());
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
}
}
公共类WeatherHourlyForecastGraphView扩展视图{
私有静态字符串LOG_TAG=WeatherHourlyForecastGraphView.class.getSimpleName();
专用静态内部温度=0;
私有静态int=1;
私有静态最终字符串时间\u FORMAT=“h a”;
//公共静态最终整数图\高度\电话=145;
//公共静态最终整型图\高度\平板=188;
公共静态final int GRAPH_TOP=(DeviceInfo.isDevicePhone()?145:186);
public static final int GRAPH\u DISPLAY\u HEIGHT=GRAPH\u TOP-9;//100将以GRAPH\u DISPLAY\u HEIGHT显示
私有Rect mTextBounds;
//正在点击的图形中的句柄小时数
OnHourSelectListener上的公共接口{
已选择小时无效(int SELECTED POSITION);
}
//温度和降水值
私有ArrayList MPRecipationValues=新ArrayList();
private ArrayList mTemperatureValues=new ArrayList();
//天气的当前城市-为此城市每小时检索一次
私人城市McCurrentCityWeather;
//图标
私有HashMap mWeatherConditionIcons=新HashMap();
沉淀法;
//油漆
私家漆;温度漆;
私人涂料;沉淀涂料;
私人涂料;沉淀漆;
私人涂料、纸面涂料;
私人涂料;
私人油漆;
私人涂料;
私家漆mTemperatureTextPaint;
私人涂料;沉淀涂料;
私人涂料-精选涂料;
//选择小时后。重新绘制图表,更新条件
私人int mSelectedPosition;
私有OnHourSelectionListener mOnHourSelectionListener;
private GestureDetector.SimpleOnGestureListener gestureListener=新建gestureListener();
私有最终GestureDetector GestureDetector=新的GestureDetector(getContext(),gestureListener);
//在图形中显示单个小时的宽度(x值)
私有整数mHalfHourlyDisplayWidth;
私有int mHourlyDisplayWidth;
私有整数加总;
私有int IContopadding;
私有int添加;
私有整数预加;
带填充的专用内部高度;
私人国际会议中心;
私有RectF-mIconRectF;
私人整数小时=24;
私人涂料背景涂料;
专用路径tempGeneratePath;
私人MyNews MyNews;
ArrayList路径值;
公共天气小时ForecastGraphView(上下文){
超级(上下文);
}
公共天气小时ForeCastGraphView(上下文上下文,属性集属性){
超级(上下文,attrs);
}
公共WeatherHourlyForecastGraphView(上下文上下文、属性集属性、int defStyleAttr){
super(上下文、attrs、defStyleAttr);
}
@TargetApi(Build.VERSION\u code.LOLLIPOP)
public WeatherHourlyForecastGraphView(上下文上下文、属性集属性、int-defStyleAttr、int-defStyleRes){
super(context、attrs、defStyleAttr、defStyleRes);
}
{
mIconRectF=新的RectF();
backgroundPaint=新油漆();
tempGeneratePath=新路径();
myNews=myNews.getMyNews();
pathValues=新的ArrayList();
初始化paintsinus();
初始化尺寸();
mpReciptionion=BitmapFactory.decodeResource(getResources(),R.drawable.rain\u drop);
mTextBounds=new Rect();//用于在绘图时计算文本边界。在构造函数中初始化以避免在onDraw()中创建对象
//setLayerType(层类型软件,空);
}
private void initializePaintSinsuse()的初始值{
MTTemperaturePaint=新油漆(油漆.防油漆别名标志);
mTemperaturePaint.setColor(ContextCompat.getColor(getContext(),R.color.hourly\u forecast\u graph\u temperature\u color));
M温度油漆。设定行程宽度(3);
MTTemperaturePaint.setStyle(绘制样式笔划);
MPRecipationPaint=新油漆(油漆.防油漆别名标志);
mpRecipationPaint.setColor(ContextCompat.getColor(getContext(),R.color.hourly\u forecast\u graph\u precip\u color));
M沉淀漆。设置行程宽度(3);
MPRecipationLinePaint=新油漆(油漆.防油漆别名标志);
mpRecipationLinePaint.setColor(ContextCompat.getColor(getContext(),R.color.hourly\u forecast\u graph\u precip\u line\u color));
M沉淀在线涂漆。设置行程宽度(3);
MPRecipationLinePaint.setStyle(绘制.样式.笔划);
mGraphPaperLinePaint=新油漆(油漆.防油漆别名标志);
mGraphPaperLinePaint.setColor(ContextCompat.getColor(getContext(),R.color.hourly\u forecast\u graph\u paper\u line\u color));
调整行程宽度(1);
mGraphPaperLinePaint.setPathEffect(null);
mGraphPaperLinePaint.setStyle(Paint.Style.STROKE);
mWhitePaint=新油漆(油漆。防油漆别名标志);
mWhitePaint.setColor(Color.WHITE);
mWhitePaint.setStrokeWidth(DeviceInfo.getValuesInPixel(1));
mSelectedPaint=新油漆(油漆.防油漆别名标志);
mSelectedPaint.setColor(ContextCompat.getColor(getContext(),R.color.hourly\u forecast\u graph\u selected\u item\u color));
M选择的油漆。设置行程宽度(2);
mDotPaint=新油漆(油漆.防油漆别名标志);
setColor(ContextCompat.getColor(getContext(),R.color.pale_blue));
mDotPaint.设定行程宽度(2);
mTimeTextPaint=新油漆(油漆.防油漆别名标志);
mTimeTextPaint.setColor(ContextCompat.getColor(getContext(),R.color.hourly\u forecast\u graph\u time\u text\u color));
mTimeTextPaint.setTextSize(getResources().getDimension(R.dimen.hourly\u forecast\u graph\u time\u text\u size));