안 드 로 이 드 는 위 챗 과 QQ 다 중 그림 을 합 친 프레임 워 크(그룹 이미지 유사)의 실현 방법 을 모방 합 니 다.
10895 단어 android작은 편지단체 채 팅 프로필 사진
현재 대부분의 app 에 채 팅 을 넣 는 것 은 이미 매우 보편적 인 현상 이 고,위 챗 과 qq 는 통신 분야 의 원조 이다.제품 매니저 가 채 팅 디자인 을 고려 할 때 대부분 참고 한다.
자주 들 을 수 있 습 니 다.위 챗 과 qq 가 모두 이렇게 하 는 것 을 보 세 요.그렇게 하 세 요.마음 이 만 가지 불쾌 하지만 누가 우 리 를 추구 하 는 프로그래머 라 고 부 릅 니까?
그래서 제품 의 요 구 는 위 챗 과 유사 한 군 두상 을 실현 하 는 것 이다.
유사 하 다
프로그래머 로 서 우선 업 무량 을 평가 해 보 겠 습 니 다.제품 눈 에는 그림 을 합성 하 는 거 잖 아 요.뭐 가 어려워 요?그래서 근무 시간 에 어떻게 할 수 있 을 지 결 정 했 죠.
프로젝트 분석:
방안 1.레이아웃 으로 직접 작성 한 다음 에 서로 다른 레이아웃 에 따라 서로 다른 장의 그림 을 불 러 옵 니 다.모두 가 사용 하 는 그림 로드 방안 은 비동기 로 불 러 옵 니 다.그러면 불 러 올 때 반 짝 거 리 며 그림 으로 합 쳐 집 니 다.현재 그림 프레임 워 크 에 캐 시 가 있 기 때문에 두 번 째 는 많이 좋아 질 것 입 니 다.
장점:실현 이 빠르다
단점:low 입 니 다.프로그래머 를 강요 하 는 방법 이 아니 라 효과 도 좋 지 않 습 니 다.
프로젝트 2.컨트롤 을 사용자 정의 하거나 다른 방식 으로 모든 그림 을 다운로드 합 니 다.컨트롤 에 계수 기 를 추가 하여 모든 그림 다운로드 가 완 료 된 후에 함께 표시 하도록 합 니 다.
장점:난이도 적당
단점:확장 성 이 떨 어 지 는데 언제 제품 을 합성 방안 으로 바 꾸 고 싶 어 요?
프로젝트 3.네 이 티 브 컨트롤 을 사용 하여 그룹 이미 지 를 합 친 후에 새로운 이미 지 를 만 들 고 원래 의 캐 시 를 합 니 다.병합 알고리즘 을 인터페이스 로 추상 화하 다.
장점:확장 이 쉽 고 체험 이 좋다.
단점:시간 이 좀 더 걸린다
물론 꿈 이 있 는 프로그래머 로 서 우 리 는 실현 방안 3 을 고려 하고 제품 에 시 달 리 는 프로그램 원숭이 동 포 를 행복 하 게 해 야 한다.
다음은 주요 아이디어 와 핵심 코드 를 말씀 드 리 겠 습 니 다.
사고의 방향 을 실현 하 다.
사실 전체적인 사고방식 은 말하자면 비교적 간단 하기 때문에 한 폭 의 흐름 도로 요약 할 수 있다.
실현 방법
우선,프로그램의 입력 매개 변 수 는 ImageView 컨트롤,url 목록 이 어야 한 다 는 것 을 알 고 있 습 니 다.
ImageView 이미지 보 기 는 View 클래스 에서 직접 계승 합 니 다.주요 기능 은 그림 을 표시 하 는 데 사 용 됩 니 다.실제로 그림 을 표시 할 수 있 을 뿐만 아니 라 모든 Drawable 대상 은 ImageView 로 표시 할 수 있 습 니 다.ImageView 는 모든 레이아웃 에 적용 할 수 있 으 며,Android 는 크기 조정 과 착색 작업 을 제공 합 니 다.
물론 통합 반전 함수 도 있 습 니 다.통합 방법 을 사용자 정의 하 는 데 사 용 됩 니 다.
public void displayImages(
final List<String> urls,
final ImageView imageView,
final MergeCallBack mergeCallBack
)
사고방식 에 따라,우 리 는 urls 에 따라 새 키 를 생 성하 여 캐 시가 합 쳐 진 그림 에 사용 해 야 하 며,다음 에는 캐 시 에서 직접 불 러 올 수 있 습 니 다.통합 프로필 은 시간 이 걸 리 니까.
public String getNewUrlByList(List<String> urls, String mark) {
StringBuilder sb = new StringBuilder();
for (String url : urls) {
sb.append(url + mark);
}
return sb.toString();
}
여 기 는 모든 url 을 간단하게 연결 한 다음 에 md5.캐 시 처리 가 가장 중요 한 절차 입 니 다.단일 링크 그림 의 캐 시 와 병합 그림 의 캐 시 와 관련 됩 니 다.캐 시 시스템 에 있어 서 한 장의 그림 과 여러 장의 그림 은 똑 같이 취급 되 고 모두 key 가 하나의 캐 시 대상 에 대응 합 니 다.다만 키 의 규칙 은 조금 다르다.
캐 시 방안 도 일반적인 DiskLruCache 와 Memory LruCache 가 구현 하 는 2 급 캐 시 로 캐 시의 효율 성 을 유지 할 수 있 습 니 다.(LRu 알고리즘 에 대해 서 는 간단 한 Least Recently Used,즉 최근 사용 원칙,구체 적 으로 바 이 두 를 바 랍 니 다)입 니 다.
디 스 플레이 이미지 의 핵심 코드 를 살 펴 보 겠 습 니 다.메모리 캐 시 를 찾 은 다음 디스크 캐 시 를 찾 는 것 입 니 다.없 으 면 모든 그림 을 동기 화 하 는 것 입 니 다.
public void displayImages(final List<String> urls, final ImageView imageView, final MergeCallBack mergeCallBack, final int dstWidth, final int dstHeight) {
if (urls == null || urls.size() <= 0) {
throw new IllegalArgumentException("url ");
}
if (mergeCallBack == null) {
throw new IllegalArgumentException("mergeCallBack ");
}
final String url = getNewUrlByList(urls, mergeCallBack.getMark());
imageView.setTag(IMG_URL, url);
//
Bitmap bitmap = loadFromMemory(url);
if (bitmap != null) {
LogUtil.e(Tag, "displayImages this is from Memory");
imageView.setImageBitmap(bitmap);
return;
}
try {
//
bitmap = loadFromDiskCache(url, dstWidth, dstHeight);
if (bitmap != null) {
LogUtil.e(Tag, "displayImages this is from Disk");
imageView.setImageBitmap(bitmap);
return;
}
} catch (Exception e) {
e.printStackTrace();
}
//
bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_launcher_round);
imageView.setImageBitmap(bitmap);
LogUtil.e(Tag, "displayImages this is from default");
// , 。 , 。
Runnable loadBitmapTask = new Runnable() {
@Override
public void run() {
ArrayList<Bitmap> bitmaps = loadBitMaps(urls, dstWidth, dstHeight);
if (bitmaps != null && bitmaps.size() > 0) {
Result result;
if (mergeCallBack != null) {
Bitmap mergeBitmap = mergeCallBack.merge(bitmaps, mContext, imageView);
if (urls.size() == bitmaps.size()) {
//
try {
saveDru(url, mergeBitmap);
} catch (IOException e) {
e.printStackTrace();
}
} else {
LogUtil.e(Tag, "size change. so can not save");
}
LogUtil.e(Tag, "displayImages this is from Merge");
result = new Result(mergeBitmap, url, imageView);
} else {
result = new Result(bitmaps.get(0), url, imageView);
}
Message msg = mMainHandler.obtainMessage(MESSAGE_SEND_RESULT, result);
msg.sendToTarget();
}
}
};
threadPoolExecutor.execute(loadBitmapTask);
}
캐 시 에서 불 러 오 는 데 실패 하면 스 레 드 를 열 어 이미지 통합 작업 을 수행 합 니 다.그 이미지 통합 은 동기 화 작업 입 니 다.이미지 통합 이 필요 한 대상 을 얻어 야 합 니 다.어떻게 얻 을 수 있 습 니까?우 리 는 코드 를 계속 봅 니 다.
private ArrayList<Bitmap> loadBitMaps(List<String> urls, int dstWidth, int dstHeight) {
ArrayList<Bitmap> bitmaps = new ArrayList<>();
for (String url : urls) {
//
Bitmap bitmap = loadBitMap(url, dstWidth, dstHeight);
if (bitmap != null) {
bitmaps.add(bitmap);
}
}
return bitmaps;
}
그림 은 loadBitMap()함 수 를 통 해 되 돌아 오 는 것 이 고 이 함수 의 핵심 방법 은?
private Bitmap loadBitMap(String url, int dstWidth, int dstHeight) {
//
Bitmap bitmap = loadFromMemory(url);
if (bitmap != null) {
LogUtil.e(Tag, "this is from Memory");
return bitmap;
}
try {
//
bitmap = loadFromDiskCache(url, dstWidth, dstHeight);
if (bitmap != null) {
LogUtil.e(Tag, "this is from Disk");
return bitmap;
}
//
bitmap = loadFromNet(url, dstWidth, dstHeight);
LogUtil.e(Tag, "this is from Net");
if (bitmap == null) {
LogUtil.e(Tag, "bitmap null network error");
}
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
디 스 플레이 이미지()방법의 논리 에 똑 같은 캐 시 방향 을 사용 한 것 을 똑똑히 볼 수 있 습 니 다.우 리 는 다시 loadBitmapTask 라 는 스 레 드 의 실행 방법 으로 돌아 갑 니 다.그 중에서 중요 한 논 리 는?
Bitmap mergeBitmap = mergeCallBack.merge(bitmaps, mContext, imageView);
if (urls.size() == bitmaps.size()) {
//
try {
saveDru(url, mergeBitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
이 mergeCallBack 방법 은 사용자 가 스스로 실현 해 야 할 이미지 통합 방법 입 니 다.목록 의 bitmap 에 들 어간 다음 병합 그림 대상 을 되 돌려 줍 니 다.마지막 으로 이 통합 을 캐 시 에 추가 합 니 다.다음 부 터 는 캐 시 에서 바로 찾 을 수 있 습 니 다.다음 의 중점 은 이미지 통합 기술 이다.저 는 코드 에 위 챗 과 qq 를 실현 하 는 그룹 프로필 사진 을 넣 었 습 니 다.다음은 위 챗 합병 방안,QQ 의 합병 방안 을 간단하게 말씀 드 리 겠 습 니 다.여러분 은 스스로 코드 를 보 러 갈 수 있 습 니 다.
우선 MergeCallBack 의 실현 방법 을 살 펴 보 겠 습 니 다.
@Override
public Bitmap merge(List<Bitmap> bitmapArray, Context context, ImageView imageView) {
this.context = context;
//
ViewGroup.LayoutParams lp = imageView.getLayoutParams();
int tempWidth;
int tempHeight;
if (lp != null) {
tempWidth = dip2px(context, lp.width);
tempHeight = dip2px(context, lp.height);
} else {
//
tempWidth = dip2px(context, 70);
tempHeight = dip2px(context, 70);
}
return CombineBitmapTools.combimeBitmap(context, tempWidth, tempHeight,
bitmapArray);
}
combineBitmap 의 실현 을 살 펴 보 겠 습 니 다.
public static Bitmap combimeBitmap(Context context, int combineWidth,
int combineHeight, List<Bitmap> bitmaps) {
if (bitmaps == null || bitmaps.size() == 0)
return null;
if (bitmaps.size() >= 9) {
bitmaps = bitmaps.subList(0, 9);
}
Bitmap resultBitmap = null;
int len = bitmaps.size();
// , 。
List<CombineBitmapEntity> combineBitmapEntities = CombineNineRect
.generateCombineBitmapEntity(combineWidth, combineHeight, len);
//
List<Bitmap> thumbnailBitmaps = new ArrayList<Bitmap>();
for (int i = 0; i < len; i++) {
thumbnailBitmaps.add(ThumbnailUtils.extractThumbnail(bitmaps.get(i),
(int) combineBitmapEntities.get(i).width,
(int) combineBitmapEntities.get(i).height));
}
//
resultBitmap = getCombineBitmaps(combineBitmapEntities,
thumbnailBitmaps, combineWidth, combineHeight);
return resultBitmap;
}
private static Bitmap getCombineBitmaps(
List<CombineBitmapEntity> mEntityList, List<Bitmap> bitmaps,
int width, int height) {
Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
for (int i = 0; i < mEntityList.size(); i++) {
//
newBitmap = mixtureBitmap(newBitmap, bitmaps.get(i), new PointF(
mEntityList.get(i).x, mEntityList.get(i).y));
}
return newBitmap;
}
마지막 으로 getCombineBitmaps 를 호출 하여 이미 지 를 합성 하 는 관건 은 Bitmap.createBitmap 를 통 해 이 루어 지 는 것 입 니 다.
private static Bitmap mixtureBitmap(Bitmap first, Bitmap second,
PointF fromPoint) {
if (first == null || second == null || fromPoint == null) {
return null;
}
Bitmap newBitmap = Bitmap.createBitmap(first.getWidth(),
first.getHeight(), Bitmap.Config.ARGB_8888);
Canvas cv = new Canvas(newBitmap);
cv.drawBitmap(first, 0, 0, null);
cv.drawBitmap(second, fromPoint.x, fromPoint.y, null);
cv.save(Canvas.ALL_SAVE_FLAG);
cv.restore();
if (first != null) {
first.recycle();
first = null;
}
if (second != null) {
second.recycle();
second = null;
}
return newBitmap;
}
모든 관건 적 인 논 리 는 코드 에 이미 비고 되 어 있다.전체 효과 와 전체 코드 를 보고 싶다 면 여 기 를 클릭 하 십시오.MutiImgLoader물론로 컬 다운로드을 통 해서 도 됩 니 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.