제가 그동안 올린 포스팅을 보면 SPAN TAG를 활용하는 작업을 주로 적었습니다. 이번에는 그 모든 것을 합쳐 하나의 형태로 꾸며 보았습니다.


전체적인 모양 틀은 위와 같습니다. TextView, Button 5개, EditText 하나를 추가시켜준 단순한 형태입니다. 이 상태에서 TextWatcher를 통해 EditText를 지속적으로 감시해줍니다. 제가 코딩을 잘 못하기 때문에 소스가 난잡하지 않고 정직 하게 노가다성으로 짰습니다.

 // Button Listener
 Button.OnClickListener mClick = new OnClickListener()
 {
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch(v.getId())
		{
		case R.id.btn1:	// Add Image
			int currentCursorStart = m_edtComposer.getSelectionStart();
					
			Bitmap bm = BitmapFactory.decodeResource(getResources(),R.drawable.icon);
			m_edtComposer.getText().insert(currentCursorStart, "\uFFFC");
			m_edtComposer.getText().setSpan(new ImageSpan(bm), currentCursorStart, currentCursorStart+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			break;
		case R.id.btn2: 
			if((mode & 0x0001) == 0x0001)
				mode = mode & 0x1110;
			else 
				mode = mode | 0x0001;
			break;
		case R.id.btn3:
			if((mode & 0x0010) == 0x0010)
				mode = mode & 0x1101;
			else 
				mode = mode | 0x0010;
			break;
		case R.id.btn4:
			if((mode & 0x0100) == 0x0100)
				mode = mode & 0x1011;
			else 
				mode = mode | 0x0100;
			break;
		case R.id.btn5:
			if((mode & 0x1000) == 0x1000)
				mode = mode & 0x0111;
			else 
				mode = mode | 0x1000;
			break;
		}
		// Log : Bit Test
		Log.d("YSK","[YSK] mode : "+Integer.toHexString(mode));
	}
    	
 };


버튼 리스너는 각각에 맞춰 Bit연산으로 처리 했습니다. 맨 밑에 Log를 찍어 현재 값이 정상적인지 확인 하고 있습니다. 여기서 특별히 봐야 하는 부분은 Button 1번인 이미지 처리 버튼입니다. imageSpan을 이용해 이미지를 추가하는데 예전 포스팅을 살펴보면 append를 image로 주고 length인 5만큼 공간을 할당해서 imagespan을 먹였는데 이렇게 하면 span값이 정상적으로 입혀지지 않고 그 사이의 공간을 별도로 처리 하게 됩니다. 그래서 insert를 이용해 위와 같이 처리를 하면 기타 문제가 발생하지 않더군요. insert의 용도를 다시한번 살펴봐야겠습니다. 

@Override
public void onTextChanged(CharSequence s, int start, int before,
		int count) {
	// TODO Auto-generated method stub
	Log.d("YSK", "[YSK] START : "+start+" BEFORE : "+before+" COUNT : "+count);
			
	if((mode & 0x001) == 0x001) {
		m_edtComposer.getText().setSpan(new ForegroundColorSpan(Color.BLUE),start,start+count, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		m_edtComposer.setSelection(m_edtComposer.getSelectionEnd());
	}else {
		m_edtComposer.getText().setSpan(new ForegroundColorSpan(Color.BLACK),start,start+count, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		m_edtComposer.setSelection(m_edtComposer.getSelectionEnd());	
	}
	
	if((mode & 0x0010) == 0x0010) {
		m_edtComposer.getText().setSpan(new StyleSpan(Typeface.BOLD),start,start+count, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		m_edtComposer.setSelection(m_edtComposer.getSelectionEnd());
	}else {
		m_edtComposer.getText().setSpan(new StyleSpan(Typeface.NORMAL),start,start+count, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		m_edtComposer.setSelection(m_edtComposer.getSelectionEnd());	
	}
	
	if((mode & 0x0100) == 0x0100) {
		m_edtComposer.getText().setSpan(new StyleSpan(Typeface.ITALIC),start,start+count, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		m_edtComposer.setSelection(m_edtComposer.getSelectionEnd());
	}else {
		m_edtComposer.getText().setSpan(new StyleSpan(Typeface.NORMAL),start,start+count, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		m_edtComposer.setSelection(m_edtComposer.getSelectionEnd());	
	}
			
	if((mode & 0x1000) == 0x1000) {
		m_edtComposer.getText().setSpan(new UnderlineSpan(),start,start+count, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		m_edtComposer.setSelection(m_edtComposer.getSelectionEnd());
	}else {
		m_edtComposer.getText().setSpan(new SpannableStringBuilder(), start, start+count, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
		m_edtComposer.setSelection(m_edtComposer.getSelectionEnd());	
	}
}

리스너에서는 앞에서 만든 mode값을 처리해 주는 작업을 하고 있습니다. new StyleSpan을 미리 정해놓고 하게 되면 속도 향상은 있지만 매글자마다 별도로 작업을 처리해주더군요. 이러한 상황을 없애기 위해서는 매번 불려지는 값에서 span값을 가져와 그 span을 처리해주는 작업이 필요합니다. 여기서는 그러한 작업은 하지 않았습니다.

막상 적어 놓고 보니, 많이 어설픈 구석이 많네요..
저작자 표시 비영리 동일 조건 변경 허락
크리에이티브 커먼즈 라이선스
Creative Commons License