안녕하십니까 초보 앱 개발자 입니다.
제가 궁금한 것은 다음과 같습니다.
- 목적 : 아날로그 시계위젯 구현
- 진행
1. 소스코드 상에서 아날로그 시계 구현 (public class analogclock extends activity{ ... ) - 이건 그냥 돌리면 app 뜨면서 잘 돌아감
2. 위젯으로 구현하기 위해 res/layout/main.xml 에 소스코드 연결 (커스텀 뷰 이용)
* appwidgetprovider 클래스 내에서 remoteviews 쓰기 위해서는 R.layout. XX 를 쓰지 않고서는 위젯 구현이 힘들기에 그렇게 적용
3. 문제 : 소스코드를 layout에 연결해도 remoteviews에서 지원하는 element 들은 제한되어 있기 때문에 실제 위젯이 구현되지 않음
* 지원 element : linearlayout, Relativelayout, analogclock, ImageView 등등..
4. 때문에 main.xml에서 remoteViews 가 지원하는 element를 사용하고 또 다른 xml(소스코드와 연결한)을 만들어서 그것을 main.xml과
연결해 보았으나 구현 실패
제가 초보자라서 약간 알아듣기 어렵게 쓴거 같네요.;; 이해 부탁드리구요..
아래에 소스코드 몇 줄 보내드리니 문제에 대한 답변 주시면 정말 감사하겠습니다.
------------------------------------------------------------------------------------------------------------------------------------
1. 시계구현 소스코드 (원래 app으로 구현했을 때는 activity를 상속받는 클래스에서 setContentView(new ClockView(this))를 써서 구현했으나 위젯 생성을 위해 layout에 뷰를 적용시키려 다음과 같이 따로 소스코드 분리 )
package com.samsung.AnalogClockWidget2;
import java.util.Calendar;
import java.util.GregorianCalendar;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Handler;
import android.os.Message;
import android.view.View;
public class ClockView extends View {
Canvas mCanvas;
private Bitmap mClock;
private Bitmap mCenter;
private Bitmap mPin[] = new Bitmap[3];
public ClockView(Context context) {
super(context);
// TODO Auto-generated constructor stub
mHandler.sendEmptyMessageDelayed(0, 1000);
}
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
//super.handleMessage(msg);
drawClock(mCanvas);
invalidate();
mHandler.sendEmptyMessageDelayed(0, 1000);
}
};
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
//super.onDraw(canvas);
mClock = BitmapFactory.decodeResource(this.getResources(), R.drawable.dial);
mCenter = BitmapFactory.decodeResource(this.getResources(), R.drawable.center);
mPin[0] = BitmapFactory.decodeResource(this.getResources(), R.drawable.sec_n2);
mPin[1] = BitmapFactory.decodeResource(this.getResources(), R.drawable.min_n2);
mPin[2] = BitmapFactory.decodeResource(this.getResources(), R.drawable.hour_n2);
mCanvas = canvas;
drawClock(canvas);
}
private void drawClock(Canvas canvas) {
// TODO Auto-generated method stub
GregorianCalendar mCalendar = new GregorianCalendar();
int hour = mCalendar.get(Calendar.HOUR);
int min = mCalendar.get(Calendar.MINUTE);
int sec = mCalendar.get(Calendar.SECOND);
float rSec = sec *6 ;
// 360도 / 60초 = 6도/초
float rMin = min*6 + rSec/60;
//
float rHour = hour*30 + rMin/12 ;
int w = mClock.getWidth()/2;
// 반폭
int h = mClock.getHeight()/2;
int w1=mPin[0].getWidth()/2;
int h1=mPin[0].getHeight()-28;
int w2=mPin[1].getWidth()/2;
int h2=mPin[1].getHeight()-15;
int w3=mPin[2].getWidth()/2;
int h3=mPin[2].getHeight()-15;
int w4=mCenter.getWidth()/2;
int h4=mCenter.getHeight()-40;
int cx = getWidth()/2;
int cy = getHeight()/2;
canvas.drawBitmap(mClock, cx-w, cy-h, null);
canvas.rotate(rHour,cx,cy);
canvas.drawBitmap(mPin[2],cx-w3,cy-h3,null);
//시침 맨아래
canvas.rotate(rMin-rHour,cx,cy);
canvas.drawBitmap(mPin[1],cx-w2,cy-h2,null);
canvas.rotate(rSec-rMin,cx,cy);
canvas.drawBitmap(mPin[0],cx-w1,cy-h1,null);
//초침 맨위에
canvas.rotate(-rSec,cx,cy);
canvas.drawBitmap(mCenter, cx-w4, cy-h4, null);
}
}
2. layout/main.xml 코드 : remoteviews가 커스텀뷰를 지원하지 않기 때문에 간접적으로 접근하도록 꾸밈
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/clock"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
</RelativeLayout>
3. drawable/clock.xml : 소스코드와 연결
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<com.sec.AnalogClockWidget2.AnalogClock_Custom
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
4. appwidgetprovider 소스
package com.samsung.AnalogClockWidget2;
import java.util.Calendar;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.ImageView;
import android.widget.RemoteViews;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;
public class AnalogClockWidget2 extends AppWidgetProvider{
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
// TODO Auto-generated method stub
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
appWidgetManager.updateAppWidget(appWidgetIds, views);
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
그냥 ImageView 하나 layout으로 만드시구요.
위젯에 비트맵 하나 만들어 놓고 그려야 할 때마다 비트맵에 그리면 됩니다.
제 어플중에 동서남북 나침반 보시면 아는데요.
imageview에 비트맵 갱신시키는 방식으로 했습니다.
아실지 모르겠지만 비트맵에서 canvas를 얻을 수 있거든요.
이 부분 공부해 보시면 될 것입니다~!
레이아웃으로 imageview나 textview 있는 것들 그릴때 바꿔치자나요
그러니까 레이아웃에 imageview 하나 만들고 fill_parent해놓고
그림 그릴때마다 하던 아니면 한 번 만들고 쓰던
buffer <- Bitmap , 아래는 2 by 2사이즈 위젯
if( buffer == null ){
DisplayMetrics metrics = new DisplayMetrics();
WindowManager wm = (WindowManager)cont.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(metrics);
width = (int)(146*metrics.density);
height = (int)(146*metrics.density);
buffer = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
}
이렇게 해서 버퍼 비트맵 만드시고 buffer에서 canvas 얻어서 그리시고
remoteviews.setImageViewBitmap
로 한 개 뿐인 이미지뷰를 갈아치시는 방향으로
주기적으로 하시면 됩니다..
제가 검색해서 알게 된 내용이니 뒤지면 나옵니다.
위에 분은 뭔가 해주신다는데 제가 시간이 넘쳐흐르지 않기 때문에 검색해서 하시는게 편하실듯..
간단히 설명하면 "위젯 크기의 프레임 버퍼 만들어서 그리고 이걸 주기적으로 갱신한다"
시계니까 일정 시간 단위로 하시면 되겠지요.
AndroidManifestxml 에도 Receiver를 등록해 주어야 합니다.. 아래와 같이요..
<receiver android:name=".ExampleAppWidgetProvider" android:label="Scriptures Daily">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/example_appwidget_info" />
</receiver>
저를 믿으신다면 소스를 gudoshi@gmail.com 으로 보내 주시면 성심성의껏 도움을 드리겠습니다..