아직 1년이 조금 안되는 안드로이드 개발자 입니다.
사수 개발자가 없어서 지금 제가 하는 방법이 맞는지 확인할 수 없어서 질문 올려봅니다.
현재 제가 만드는 앱은 ImageView와 Bitmap이 화면을 이루고 있습니다.
ImageView는 위치가 변하지 않는 이미지를 올려서 그리게 하고, Bitmap은 onDraw 함수를 이용하여 그립니다.
Bitmap을 onDraw 함수를 이용하여 애미메이션 효과를 구현하였습니다.
그런데 ImageView와 Bitmap 이미지를 화면에 배치할 때 xml로 하기에는 한계가 있습니다.
ViewGroup의 레이아웃에 맞게 위치시키기에는 힘들고 하여,
xml로는 ImageView 객체만 생성하고 java 코드로 재배치 합니다.
(안드로이드 해상도가 다 다르기에 해상도를 계산하여 배치하는 방식으로 java 코딩)
이러한 방식으로 하니깐 view와 Bitmap 이미지 재배치 하는 코드만 150줄 이상이 나옵니다.
그리고 앱이 시작할 때 view를 재배치하는 시간때문에 약간의 딜레이가 있습니다.
고수분들은 해상도에 맞게 동적으로 view를 배치할 때 어떠한 방식으로 하시는 지 궁금합니다.
좋은 조언 부탁드립니다.
짧지 않은글 읽어주셔서 감사합니다.
아래는 실제 제가 재비치하는 코딩부분입니다.
Resources resources = getResources();
//화면 폭 3등분. 2 : 1 비율
int leftScrWidth = mScrDivisionPoint = Math.round(mScrWidth/3);
int rightScrWidth = leftScrWidth*2;
//화면 높이 10등분
int scrHeightPixel = Math.round(mScrHeight/10);
int leftScrWidthPixel = Math.round(leftScrWidth/10);
int rightScrWidthPixel = rightScrWidth/25;
int mVMappingValue = Math.round(scrHeightPixel/6);
int vertiBaseImgHeight = scrHeightPixel*6;
mVertiDirMinY = (scrHeightPixel*3) - mVMappingValue;
//좌측 게이지 이미지 뷰
int speedBarPosPixel = Math.round(vertiBaseImgHeight/18);
int modificationPixel = Math.round(speedBarPosPixel/3);
int speedBarBaseTopMargin = modificationPixel + mVertiDirMinY;
mSpeedBarGoViews[3] = (ImageView)findViewById(R.id.speedBar0);
mSpeedBarBlank = BitmapFactory.decodeResource(resources, R.drawable.speed_bar_blank);
int SpeedBarHeight = Math.round(scrHeightPixel/2);
int vertiDirImgHeight = Math.round(scrHeightPixel*21/17);
int speedBarImgWidth = leftScrWidthPixel*2;
mSpeedBarBlank = Bitmap.createScaledBitmap(mSpeedBarBlank, speedBarImgWidth, SpeedBarHeight, true);
mSpeedBarGoViews[3].setImageBitmap(mSpeedBarBlank);
((LinearLayout.LayoutParams)mSpeedBarGoViews[3].getLayoutParams()).setMargins(
leftScrWidthPixel*2, speedBarBaseTopMargin, 0, 0);
mSpeedBarGoBasePos[3] = speedBarBaseTopMargin;
String packageName = getContext().getPackageName();
int rscId = 0;
int leftMargin = leftScrWidthPixel*(-2);
int topMargin = 0;
int viewId = 1;
for(i=2; i>=0; i--){
rscId = resources.getIdentifier("speedBar"+(viewId), "id", packageName);
mSpeedBarGoViews[i] = (ImageView)findViewById(rscId);
mSpeedBarGoViews[i].setImageBitmap(mSpeedBarBlank);
topMargin = (speedBarPosPixel*(viewId++)*2)+speedBarBaseTopMargin;
((LinearLayout.LayoutParams)mSpeedBarGoViews[i].getLayoutParams()).setMargins(
leftMargin, topMargin, 0, 0);
mSpeedBarGoBasePos[i] = topMargin;
}
ImageView SpeedBarCenterView = (ImageView)findViewById(R.id.speedBar4);
Bitmap defaultBarImg = BitmapFactory.decodeResource(resources, R.drawable.speed_bar_0);
defaultBarImg = Bitmap.createScaledBitmap(defaultBarImg, speedBarImgWidth, SpeedBarHeight, true);
SpeedBarCenterView.setImageBitmap(defaultBarImg);
((LinearLayout.LayoutParams)SpeedBarCenterView.getLayoutParams()).setMargins(
leftMargin, (speedBarPosPixel*(viewId++)*2)+speedBarBaseTopMargin, 0, 0);
for(i=0; i<4; i++){
rscId = resources.getIdentifier("speed_bar_"+(i+1), "drawable", packageName);
mSpeedBarImgs[i] = BitmapFactory.decodeResource(resources, rscId);
mSpeedBarImgs[i] = Bitmap.createScaledBitmap(
mSpeedBarImgs[i], speedBarImgWidth, SpeedBarHeight, true);
rscId = resources.getIdentifier("speedBar"+(viewId), "id", packageName);
mSpeedBarBackViews[i] = (ImageView)findViewById(rscId);
mSpeedBarBackViews[i].setImageBitmap(mSpeedBarBlank);
topMargin = (speedBarPosPixel*(viewId++)*2)+speedBarBaseTopMargin;
((LinearLayout.LayoutParams)mSpeedBarBackViews[i].getLayoutParams()).setMargins(
leftMargin, topMargin, 0, 0);
mSpeedBarBackBasePos[i] = topMargin - Math.round(vertiDirImgHeight/2);
}
//상하 조정간 이미지 백그라운드 및 필요값 설정
mVertiDirMaxY = vertiBaseImgHeight + mVertiDirMinY - scrHeightPixel;
mVertiDirCenterY = Math.round(((vertiBaseImgHeight/2) + mVertiDirMinY) - vertiDirImgHeight/2);
mVertiDirCenterX = leftScrWidthPixel*5;
mVertiDirBg = BitmapFactory.decodeResource(resources, R.drawable.gage_btn_bg1);
mVertiDirBg = Bitmap.createScaledBitmap(mVertiDirBg, leftScrWidthPixel, vertiBaseImgHeight, true);
mVBgPosX = leftScrWidthPixel*6;
mVBgPosY = mVertiDirMinY;
//상하 +, - 이미지 뷰
ImageView gageBtnBg2 = (ImageView)findViewById(R.id.gageBg2);
Bitmap tempImg = BitmapFactory.decodeResource(resources, R.drawable.gage_btn_bg2);
tempImg = Bitmap.createScaledBitmap(tempImg, leftScrWidthPixel, vertiBaseImgHeight, true);
gageBtnBg2.setImageBitmap(tempImg);
((LinearLayout.LayoutParams)gageBtnBg2.getLayoutParams()).setMargins(leftScrWidthPixel*5, mVertiDirMinY, 0, 0);
//좌우 조정간 백그라운드 이미지 및 필요값 설정
int horizDirBgSize = Math.round(vertiBaseImgHeight- (int)((float)vertiBaseImgHeight*0.07f));
int horizDirWidth = Math.round(horizDirBgSize/3);
mHorizDirBg = BitmapFactory.decodeResource(resources, R.drawable.dir_bg);
mHorizDirBg = Bitmap.createScaledBitmap(mHorizDirBg, horizDirBgSize, vertiBaseImgHeight, true);
mHBgPosX = (rightScrWidthPixel*11) + leftScrWidth;
mHBgPosY = scrHeightPixel*2;
int mHMappingValue = horizDirWidth/2;
//좌우, 상하 조정간 이미지 및 필요값 설정.
mHorizDirCenterX = Math.round(mHBgPosX + (horizDirBgSize/2) - mHMappingValue);
mHorizDirCenterY = Math.round(vertiBaseImgHeight/2 + scrHeightPixel*2 - (vertiBaseImgHeight/6) + 3);
mHorizDirMinX = Math.round(mHorizDirCenterX - (horizDirWidth*2/3));
mHorizDirMaxX = Math.round(mHorizDirCenterX + (horizDirWidth*2/3));
mVertiDirImg = BitmapFactory.decodeResource(resources, R.drawable.gage_btn);
mVertiDirImg = Bitmap.createScaledBitmap(mVertiDirImg, leftScrWidthPixel*3, vertiDirImgHeight, true);
mHorizDirImg = BitmapFactory.decodeResource(resources, R.drawable.dir_btn);
mHorizDirImg = Bitmap.createScaledBitmap(mHorizDirImg, horizDirWidth,
Math.round(vertiBaseImgHeight/3), true);
mVPosX = mVertiDirCenterX;
mVPosY = mVertiDirCenterY;
mHPosX = mHorizDirCenterX;
mHPosY = mHorizDirCenterY;
//좌우 조정간 좌우측 방향 이미지(삼각형) 및 필요값 설정.
int arrowWidth = Math.round(horizDirWidth/2);
int arrowHeight = Math.round(vertiBaseImgHeight/6);
mLeftArrowOn = BitmapFactory.decodeResource(resources, R.drawable.left_on);
mLeftArrowOn = Bitmap.createScaledBitmap(mLeftArrowOn, arrowWidth, arrowHeight, true);
mLeftArrowOff = BitmapFactory.decodeResource(resources, R.drawable.left_off);
mLeftArrowOff = Bitmap.createScaledBitmap(mLeftArrowOff, arrowWidth, arrowHeight, true);
mRightArrowOn = BitmapFactory.decodeResource(resources, R.drawable.right_on);
mRightArrowOn = Bitmap.createScaledBitmap(mRightArrowOn, arrowWidth, arrowHeight, true);
mRightArrowOff = BitmapFactory.decodeResource(resources, R.drawable.right_off);
mRightArrowOff = Bitmap.createScaledBitmap(mRightArrowOff, arrowWidth, arrowHeight, true);
mLeftArrow = mLeftArrowOff;
mRightArrow = mRightArrowOff;
mLArrowPosX = mHBgPosX + 1;
mRArrowPosX = (mHBgPosX + horizDirBgSize) - arrowWidth - 2;
mArrowPosY = mHPosY + (Math.round(vertiBaseImgHeight/6)) - Math.round(arrowHeight/2);
//상단 A, B, C 버튼 좌표설정
int btnWidthPixel = Math.round(mScrWidth/8);
int btnHeightPixel = Math.round(scrHeightPixel/2);
int btnHeight = btnHeightPixel*2;
ChanelButtonListener abcBtnListener = new ChanelButtonListener();
mBtnA = (ImageView)findViewById(R.id.button_a);
mABtnOn = BitmapFactory.decodeResource(resources, R.drawable.a_btn_on);
mABtnOn = Bitmap.createScaledBitmap(mABtnOn, btnWidthPixel, btnHeight, true);
mABtnOff = BitmapFactory.decodeResource(resources, R.drawable.a_btn_off);
mABtnOff = Bitmap.createScaledBitmap(mABtnOff, btnWidthPixel, btnHeight, true);
mBtnA.setImageBitmap(mABtnOn);
mSelectedChanelId = R.id.button_a;
((LinearLayout.LayoutParams)mBtnA.getLayoutParams()).setMargins(rightScrWidthPixel*(-1), btnHeightPixel, 0, 0);
mBtnA.setOnClickListener(abcBtnListener);
mBtnB = (ImageView)findViewById(R.id.button_b);
mBBtnOn = BitmapFactory.decodeResource(resources, R.drawable.b_btn_on);
mBBtnOn = Bitmap.createScaledBitmap(mBBtnOn, btnWidthPixel, btnHeight, true);
mBBtnOff = BitmapFactory.decodeResource(resources, R.drawable.b_btn_off);
mBBtnOff = Bitmap.createScaledBitmap(mBBtnOff, btnWidthPixel, btnHeight, true);
mBtnB.setImageBitmap(mBBtnOff);
((LinearLayout.LayoutParams)mBtnB.getLayoutParams()).setMargins(0, btnHeightPixel, 0, 0);
mBtnB.setOnClickListener(abcBtnListener);
mBtnC = (ImageView)findViewById(R.id.button_c);
mCBtnOn = BitmapFactory.decodeResource(resources, R.drawable.c_btn_on);
mCBtnOn = Bitmap.createScaledBitmap(mCBtnOn, btnWidthPixel, btnHeight, true);
mCBtnOff = BitmapFactory.decodeResource(resources, R.drawable.c_btn_off);
mCBtnOff = Bitmap.createScaledBitmap(mCBtnOff, btnWidthPixel, btnHeight, true);
mBtnC.setImageBitmap(mCBtnOff);
((LinearLayout.LayoutParams)mBtnC.getLayoutParams()).setMargins(0, btnHeightPixel, 0, 0);
mBtnC.setOnClickListener(abcBtnListener);
//상하 +,- view와 좌우 조정간 빽그라운드 사이 공간 계산.
int restSpace = mHBgPosX - leftScrWidth;
int restSpacePixel = Math.round(restSpace/9);
//Turbo On,Off 버튼 좌표 설정.
int turboBtnLeftMargin = (-(btnWidthPixel*3)-rightScrWidthPixel)
+leftScrWidthPixel*2+ restSpacePixel*2;
mBtnTurbo = (ImageView)findViewById(R.id.turbo_btn);
mTurboOn = BitmapFactory.decodeResource(resources, R.drawable.turbo_on);
mTurboOn = Bitmap.createScaledBitmap(mTurboOn, restSpacePixel*5, btnHeight, true);
mTurboOff = BitmapFactory.decodeResource(resources, R.drawable.turbo_off);
mTurboOff = Bitmap.createScaledBitmap(mTurboOff, restSpacePixel*5, btnHeight, true);
mBtnTurbo.setImageBitmap(mTurboOff);
((LinearLayout.LayoutParams)mBtnTurbo.getLayoutParams()).setMargins(
turboBtnLeftMargin, btnHeightPixel*9, 0, 0);
IRButtonListener irBtnListener = new IRButtonListener();
mBtnTurbo.setOnClickListener(irBtnListener);
//rpm gauge 설정.
int rpmBgWidth = restSpacePixel*7;
int rpmBgHeight = Math.round(rpmBgWidth/2);
mRPMBg = BitmapFactory.decodeResource(resources, R.drawable.rpm_bg);
mRPMBg = Bitmap.createScaledBitmap(mRPMBg, rpmBgWidth, rpmBgHeight, true);
mRBgPosY = btnHeightPixel*4;
mRBgPosX = leftScrWidth + restSpacePixel;
int rpmCircleBgWnH = restSpacePixel;
mRPMCircleBg = BitmapFactory.decodeResource(resources, R.drawable.rpm_circle_bg);
mRPMCircleBg = Bitmap.createScaledBitmap(mRPMCircleBg, rpmCircleBgWnH, rpmCircleBgWnH, true);
mRCirclePosX = mRBgPosX + restSpacePixel*3;
mRCirclePosY = mRBgPosY + rpmBgHeight - Math.round(rpmCircleBgWnH/2);
int rpmHandWidth = Math.round(SpeedBarHeight*3/5);
int rpmHandHeight = rpmBgHeight + Math.round(rpmCircleBgWnH/3);
mRPMHand = BitmapFactory.decodeResource(resources, R.drawable.rpm_hand);
mRPMHand = Bitmap.createScaledBitmap(mRPMHand, rpmHandWidth, rpmHandHeight, true);
mRHandPivotX = mRBgPosX + Math.round(rpmBgWidth/2);
mRHandPosX = mRHandPivotX - Math.round(rpmHandWidth/2);
mRHandPivotY = mRBgPosY + rpmBgHeight;
mRHandPosY = mRBgPosY ;
아즈라엘님 답변 진심으로 감사드립니다.
1. view를 상속받아 customView를 재작성하여 xml에 추가 하시라는 말씀이시죠??
2. LinearLayout에 layout_weight를 이용한다면 빈 공간은 어떠한 방식으로 처리해야 하나요?
빈 공간에는 아무것도 없는 view를 넣어서 조절해야 하나요?
3. view같은 경우는 layout_weight를 이용하여 배치한다면, onDraw를 이용하여 그릴 Bitmap 이미지들은 각 해상도에 맞는
절대 좌표를 알고있어야 원하는 부분에 그릴수 있지않나요??
어떠한 view를 기준으로 그려질 이미지 좌표를 정할 때 activity의 onCreate() 함수가 끝나야 각 뷰의 배치가 완성되는것 같더라구요.
그래서 Handler를 이용하여 onCreate()가 끝날수 있는 시간을 딜레이를 줘서 필요한 좌표값을 구해본적은 있습니다.
이 방법보다 더 좋은 방법은 없을까요?
질문이 너무 많죠?? ^^;;
잘 하 고 싶 어 서 요 ~ ^ ^ ;
1. 맞습ㄴ디ㅏ.
2. padding은 모르겠으나 margine은 일반 View를 넣고 weight값으로 공간을 만들어야
제대로 된 값을 얻을 수 있습니다.
3. onDraw 시점이 되면 onLayout 과 onMeasure로 부터 자신의 위치와 크기를 알 수 있습니다.
onMeasure로 부터 view의 width와 height 값을 얻어와서 bitmap 을 그려내면 누더기 소스가 줄어들게
되어서 개발하시는데 빨라질겁니다.
위에 방법이 평벙한건 아닌데 지금까지 해본결과 개발속도 측면과 재사용 그리고 정적인 화면에서는 문제 없이 작동되는걸
확인하였습니다. (경험상 ~!ㅎ) 하지만 스크롤이 되면 조금 틀리게 해야 하는데 그에 따른 방법은 고민해 보시는게 좋을거 같네요




nScreen을 지원하려면 xml에서 작업하시는게 편합니다.
일일이 하드코딩하기엔 양이 너무 많아져 버리죠 ^^
원하는 뷰를 만들어 놓고 이를 xml 에 com.uesr_pkg.View 이런식으로 해서
애트리뷰트를 넣어주는데 이때 layout_weight 값을 사용하여 재배치 하도록 유도 합니다.
보통 LinearLayout 을 주로 사용하고 여기에 View를 weight으로만 채우면 스크린에 비율로 적용되기 때문에
해상도에 잘 맞게 떨어집니다.