问题描述
我想使用 Internet 上提供的 Android 开源项目的 AnalogClock 源代码制作自定义 AnalogClock 类.
I want to make a custom AnalogClock class using source code of AnalogClock by Android Open Source Project that is available in the internet.
我想让时钟设置我想要的时间,而不是当前时间.我没有找到一个明确的例子来说明如何做到这一点,所以也许这篇文章会有用.将源代码复制到新文件后,出现一些错误.下面是AnalogClock的原始源码:
I want to make the clock set the time that I want, not the current time. I didn't find a clear example on how to do it so maybe this post will be useful. After copying source code to new file, I get some errors. Below is the original source code of AnalogClock:
/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.51sjk.com/Upload/Articles/1/0/336/336513_20221114145742708.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.widget; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.BroadcastReceiver; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.os.Handler; import android.text.format.Time; import android.util.AttributeSet; import android.view.View; import android.widget.RemoteViews.RemoteView; import java.util.TimeZone; /** * This widget display an analogic clock with two hands for hours and * minutes. */ @RemoteView public class AnalogClock extends View { private Time mCalendar; private Drawable mHourHand; private Drawable mMinuteHand; private Drawable mDial; private int mDialWidth; private int mDialHeight; private boolean mAttached; private final Handler mHandler = new Handler(); private float mMinutes; private float mHour; private boolean mChanged; public AnalogClock(Context context) { this(context, null); } public AnalogClock(Context context, AttributeSet attrs) { this(context, attrs, 0); }
!!Error mContext -> 将 mContext 更改为上下文(我可以这样做)吗?
public AnalogClock(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); Resources r = mContext.getResources();
!!无法解决错误 com.android.internal.R.我找到了解决这个问题的方法
!!Error com.android.internal.R cannot be resolved. I found a solution to this problem with
mDial = r.getDrawable(Resources.getSystem().getIdentifier("clock_dial","drawable", "android"));
其他行也一样,只是更改名称和可绘制或可样式化.
And same for other lines just changing name and either drawable or styleable.
vvvv----但是下面的代码我还是有问题.
TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.AnalogClock, defStyle, 0);
^^^^----我不知道如何更改它并使其工作
mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial); if (mDial == null) { mDial = r.getDrawable(com.android.internal.R.drawable.clock_dial); } mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour); if (mHourHand == null) { mHourHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_hour); } mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute); if (mMinuteHand == null) { mMinuteHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_minute); } mCalendar = new Time(); mDialWidth = mDial.getIntrinsicWidth(); mDialHeight = mDial.getIntrinsicHeight(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (!mAttached) { mAttached = true; IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_TIME_TICK); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); getContext().registerReceiver(mIntentReceiver, filter, null, mHandler); } // NOTE: It's safe to do these after registering the receiver since the receiver always runs // in the main thread, therefore the receiver can't run before this method returns. // The time zone may have changed while the receiver wasn't registered, so update the Time mCalendar = new Time(); // Make sure we update to the current time onTimeChanged(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mAttached) { getContext().unregisterReceiver(mIntentReceiver); mAttached = false; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); float hScale = 1.0f; float vScale = 1.0f; if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) { hScale = (float) widthSize / (float) mDialWidth; } if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) { vScale = (float )heightSize / (float) mDialHeight; } float scale = Math.min(hScale, vScale); setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec), resolveSize((int) (mDialHeight * scale), heightMeasureSpec)); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mChanged = true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); boolean changed = mChanged; if (changed) { mChanged = false; }
!!!错误 - mRight、mLeft、mBotton、mTop 来自哪里?该文件中没有声明
int availableWidth = mRight - mLeft; int availableHeight = mBottom - mTop; int x = availableWidth / 2; int y = availableHeight / 2; final Drawable dial = mDial; int w = dial.getIntrinsicWidth(); int h = dial.getIntrinsicHeight(); boolean scaled = false; if (availableWidth < w || availableHeight < h) { scaled = true; float scale = Math.min((float) availableWidth / (float) w, (float) availableHeight / (float) h); canvas.save(); canvas.scale(scale, scale, x, y); } if (changed) { dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); } dial.draw(canvas); canvas.save(); canvas.rotate(mHour / 12.0f * 360.0f, x, y); final Drawable hourHand = mHourHand; if (changed) { w = hourHand.getIntrinsicWidth(); h = hourHand.getIntrinsicHeight(); hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); } hourHand.draw(canvas); canvas.restore(); canvas.save(); canvas.rotate(mMinutes / 60.0f * 360.0f, x, y); final Drawable minuteHand = mMinuteHand; if (changed) { w = minuteHand.getIntrinsicWidth(); h = minuteHand.getIntrinsicHeight(); minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); } minuteHand.draw(canvas); canvas.restore(); if (scaled) { canvas.restore(); } } private void onTimeChanged() { mCalendar.setToNow(); int hour = mCalendar.hour; int minute = mCalendar.minute; int second = mCalendar.second; mMinutes = minute + second / 60.0f; mHour = hour + mMinutes / 60.0f; mChanged = true; } private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) { String tz = intent.getStringExtra("time-zone"); mCalendar = new Time(TimeZone.getTimeZone(tz).getID()); } onTimeChanged(); invalidate(); } }; }
谁能告诉我:
- 如何让这个类像普通的 AnalogClock 一样工作
- 如何在这个类中编写一个方法来应用我将提供给它的时间?
推荐答案
使用 setTime() 方法自定义 MyAnalogClock.
花了一些时间后,我终于设法解决了这个问题.我希望它对某人有用.只需调用 setTime(hours, minutes, seconds) 方法即可设置时间.
After spending some time I finally managed to solve the problem. I hope it will be useful for someone. You can set time simply by calling setTime(hours, minutes, seconds) method.
import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.text.format.Time; import android.util.AttributeSet; import android.view.View; import android.widget.RemoteViews.RemoteView; /** * This widget display an analogic clock with two hands for hours and * minutes. */ @RemoteView public class MyAnalogClock extends View { private Drawable mHourHand; private Drawable mMinuteHand; private Drawable mSecondHand; private Drawable mDial; private int mDialWidth; private int mDialHeight; private float mSeconds; private float mMinutes; private float mHour; Context mContext; public MyAnalogClock(Context context) { super(context); } public MyAnalogClock(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyAnalogClock(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); Resources r = context.getResources(); TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.AnalogClock, defStyle, 0); mContext=context; // mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial); // if (mDial == null) { mDial = r.getDrawable(R.drawable.clock_dial); // } // mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour); // if (mHourHand == null) { mHourHand = r.getDrawable(R.drawable.clock_hour); // } // mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute); // if (mMinuteHand == null) { mMinuteHand = r.getDrawable(R.drawable.clock_minute); mSecondHand = r.getDrawable(R.drawable.clockgoog_minute); // } mDialWidth = mDial.getIntrinsicWidth(); mDialHeight = mDial.getIntrinsicHeight(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); float hScale = 1.0f; float vScale = 1.0f; if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) { hScale = (float) widthSize / (float) mDialWidth; } if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) { vScale = (float )heightSize / (float) mDialHeight; } float scale = Math.min(hScale, vScale); setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec), resolveSize((int) (mDialHeight * scale), heightMeasureSpec)); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //Here you can set the size of your clock int availableWidth = 70; int availableHeight = 70; //Actual size int x = availableWidth / 2; int y = availableHeight / 2; final Drawable dial = mDial; int w = dial.getIntrinsicWidth(); int h = dial.getIntrinsicHeight(); boolean scaled = false; if (availableWidth < w || availableHeight < h) { scaled = true; float scale = Math.min((float) availableWidth / (float) w, (float) availableHeight / (float) h); canvas.save(); canvas.scale(scale, scale, x, y); } dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); dial.draw(canvas); canvas.save(); canvas.rotate(mHour / 12.0f * 360.0f, x, y); w = mHourHand.getIntrinsicWidth(); h = mHourHand.getIntrinsicHeight(); mHourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); mHourHand.draw(canvas); canvas.restore(); canvas.save(); canvas.rotate(mMinutes / 60.0f * 360.0f, x, y); w = mMinuteHand.getIntrinsicWidth(); h = mMinuteHand.getIntrinsicHeight(); mMinuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); mMinuteHand.draw(canvas); canvas.restore(); canvas.save(); canvas.rotate(mSeconds, x, y); w = mSecondHand.getIntrinsicWidth(); h = mSecondHand.getIntrinsicHeight(); mSecondHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); mSecondHand.draw(canvas); canvas.restore(); if (scaled) { canvas.restore(); } } public void setTime(int hours, int minutes, int seconds) { mSeconds = 6.0f*seconds; mMinutes = minutes + seconds / 60.0f; mHour = hours + mMinutes / 60.0f; } }
您还应该在 drawable 文件夹中放置 4 个可绘制文件,并使用以下代码在 values 文件夹中创建(或更新)attrs 文件:
You should also put 4 drawable files in the drawable folder and create (or update) the attrs file in values folder with the following code:
<?xml version="1.0" encoding="UTF-8"?> <resources> <declare-styleable name="AnalogClock"> <attr name="dial" format="reference"/> <attr name="hand_hour" format="reference"/> <attr name="hand_minute" format="reference"/> </declare-styleable> </resources>