안 드 로 이 드 모방 위 챗 모멘트 이미지 뷰 어
효 과 는 아 쉬 운 대로 보아 라!잘 모 르 겠 으 면 위 챗 친구 권 을 생각 하거나 아래로 끌 어 내 려 가 소스 코드 를 다운로드 하 세 요!여기 서 먼저 메 인 화면 을 분석 해 보 세 요.구 조 는 모두 간단 합 니 다.메 인 화면 은 ListView 의 컨트롤 일 뿐 입 니 다.ListView 의 Item 에 주의해 야 할 것 은 Item 에 GridView 가 포함 되 어 있 습 니 다.이 GridView 는'구 궁 격'의 효 과 를 실현 하 는 데 사 용 됩 니 다.메 인 화면 구 조 는 ListView 입 니 다.여 기 는 말 할 것 도 없고 ListView 의 Item 의 구 조 를 살 펴 보 겠 습 니 다.다음은 itemlist.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="5dp"
android:paddingTop="5dp" >
<ImageView
android:id="@+id/iv_avatar"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/ic_launcher"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_toRightOf="@id/iv_avatar"
android:text=" , !"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title"
android:layout_marginLeft="5dp"
android:layout_marginTop="3dp"
android:layout_toRightOf="@id/iv_avatar"
android:text=" !"
android:textSize="16sp" />
<com.example.imagedemo.NoScrollGridView
android:id="@+id/gridview"
android:layout_width="220dp"
android:layout_height="wrap_content"
android:layout_below="@id/tv_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="3dp"
android:layout_toRightOf="@id/iv_avatar"
android:columnWidth="70dp"
android:gravity="center"
android:horizontalSpacing="2.5dp"
android:numColumns="3"
android:stretchMode="columnWidth"
android:verticalSpacing="2.5dp" />
</RelativeLayout>
자,보시 다시 피 레이아웃 도 매우 간단 합 니 다.하지만 문 제 는 ListView 가 GridView 에 끼 워 넣 었 다 는 것 입 니 다.그러면 문제 가 발생 하여 GridView 가 완전히 표시 되 지 않 습 니 다.그러면 이 문 제 를 어떻게 해결 해 야 합 니까?사실은 간단 하 다.바로 GridView 를 다시 써 서 GridView 의 높이 를 측정 한 다음 에 설정 하 는 것 이다.구체 적 인 해결 방안 은 위의 블 로그 ListView 에 포 함 된 GridView 를 보 세 요.불완전한 해결 방법 이나 소스 코드 를 보 여 줍 니 다.다음 과 같 습 니 다.NoScrollGridView.자바
package com.example.imagedemo;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.GridView;
/**
* “ ”―― :GridView , , , GridView
*
* @author lichao
* @since 2014-10-16 16:41
*
*/
public class NoScrollGridView extends GridView {
public NoScrollGridView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public NoScrollGridView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public NoScrollGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
다음은 ListView 위의 Item 의 실체 가 어떤 데이터 구조 인지 살 펴 보면 매우 간단 하 다.
public class ItemEntity {
private String avatar; // URL
private String title; //
private String content; //
private ArrayList<String> imageUrls; // URL
public ItemEntity(String avatar, String title, String content,
ArrayList<String> imageUrls) {
super();
this.avatar = avatar;
this.title = title;
this.content = content;
this.imageUrls = imageUrls;
}
...
}
자,ListView 가 있 으 면 아 이 템 의 데이터 가 어 울 리 는 것 이 불가피 합 니 다.BaseAdapter 를 계승 합 니 다.코드 는 다음 과 같 습 니 다.모두 간단 합 니 다.
/**
* ListView
*
* @author Administrator
*
*/
public class ListItemAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<ItemEntity> items;
public ListItemAdapter(Context ctx, ArrayList<ItemEntity> items) {
this.mContext = ctx;
this.items = items;
}
@Override
public int getCount() {
return items == null ? 0 : items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = View.inflate(mContext, R.layout.item_list, null);
holder.iv_avatar = (ImageView) convertView
.findViewById(R.id.iv_avatar);
holder.tv_title = (TextView) convertView
.findViewById(R.id.tv_title);
holder.tv_content = (TextView) convertView
.findViewById(R.id.tv_content);
holder.gridview = (NoScrollGridView) convertView
.findViewById(R.id.gridview);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
ItemEntity itemEntity = items.get(position);
holder.tv_title.setText(itemEntity.getTitle());
holder.tv_content.setText(itemEntity.getContent());
// ImageLoader
DisplayImageOptions options = new DisplayImageOptions.Builder()//
.showImageOnLoading(R.drawable.ic_launcher) //
.showImageOnFail(R.drawable.ic_launcher) //
.cacheInMemory(true) //
.cacheOnDisk(true) // sdcard
.bitmapConfig(Config.RGB_565)//
.build();//
ImageLoader.getInstance().displayImage(itemEntity.getAvatar(),
holder.iv_avatar, options);
final ArrayList<String> imageUrls = itemEntity.getImageUrls();
if (imageUrls == null || imageUrls.size() == 0) { // GridView
holder.gridview.setVisibility(View.GONE);
} else {
holder.gridview.setAdapter(new NoScrollGridAdapter(mContext,
imageUrls));
}
// ,
holder.gridview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
imageBrower(position, imageUrls);
}
});
return convertView;
}
/**
*
*
* @param position
* @param urls2
*/
protected void imageBrower(int position, ArrayList<String> urls2) {
Intent intent = new Intent(mContext, ImagePagerActivity.class);
// url, ,
intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_URLS, urls2);
intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_INDEX, position);
mContext.startActivity(intent);
}
/**
* listview , “ ”
*
* @author Administrator
*
*/
class ViewHolder {
private ImageView iv_avatar;
private TextView tv_title;
private TextView tv_content;
private NoScrollGridView gridview;
}
}
여기 서 설명 할 부분 이 있 습 니 다.listview 의 이미지 처 리 를 보십시오.그림 은 모두 인터넷 에서 얻 은 것 이기 때문에 그림 이 너무 많아 서 OOM 을 초래 하지 않도록 여기 서 그림 을 불 러 올 때 메모리 최 적 화 를 해 야 합 니 다.그림 의 최적화 방식 은 매우 많 습 니 다.저 는 가장 간단 하고 직접적인 방식 을 취 했 습 니 다.오픈 소스 ImageLoader 라 는 이미지 로 딩 프레임 워 크 를 사 용 했 습 니 다.이 프레임 워 크 는 정말 훌륭 합 니 다.개발 자 들 이 불필요 하고 자주 발생 하 는 번 거 로 움 을 줄 였 습 니 다.ImageLoader 에 대해 서 는 이 블 로그 에 설명 할 지식 이 아 닙 니 다.ImageLoader 에 대해 서 는 GitHub 홈 페이지 에서 다운로드 하 시기 바 랍 니 다.주 소 는?https://github.com/nostra13/Android-Universal-Image-Loader,ImageLoader 라 는 프레임 워 크 를 사용 한 이상 프로그램 에서 초기 화 작업 을 해 야 합 니 다.먼저 전체적인 컨 텍스트 애플 리 케 이 션 류 를 사용자 정의 하고 ImageLoader 의 관련 속성 을 초기 화 하 며 코드 를 직접 보 세 요.
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() //
.showImageForEmptyUri(R.drawable.ic_launcher) //
.showImageOnFail(R.drawable.ic_launcher) //
.cacheInMemory(true) //
.cacheOnDisk(true) //
.build();//
ImageLoaderConfiguration config = new ImageLoaderConfiguration//
.Builder(getApplicationContext())//
.defaultDisplayImageOptions(defaultOptions)//
.discCacheSize(50 * 1024 * 1024)//
.discCacheFileCount(100)//
.writeDebugLogs()//
.build();//
ImageLoader.getInstance().init(config);
}
}
이 애플 리 케 이 션 을 정의 한 후 목록 파일 에 설정 하고 Manifest.xml 의 애플 리 케 이 션 노드 에 추가 해 야 합 니 다.android:name="com.example.imagedemo.MyApplication"
또한 ImageLoader 는 네트워크 에서 그림 을 가 져 오고 로 컬 sdcard 캐 시 그림 이 필요 하기 때문에 권한 을 추가 해 야 합 니 다.이것 은 Imageloader 표준 권한 입 니 다.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
위 에 있 는 Item 의 데 이 터 를 살 펴 보면 그 안에 GridView 가 있 습 니 다.분명히 이 GridView 도 데이터 에 적합 해 야 합 니 다.이 데 이 터 는 네트워크 에서 그림 을 불 러 오 는 것 을 반응 합 니 다.비교적 간단 합 니 다.코드 NoScroll GridAdapter.java 를 보십시오.
......
Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = View.inflate(ctx, R.layout.item_gridview, null);
ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);
DisplayImageOptions options = new DisplayImageOptions.Builder()//
.cacheInMemory(true)//
.cacheOnDisk(true)//
.bitmapConfig(Config.RGB_565)//
.build();
ImageLoader.getInstance().displayImage(imageUrls.get(position),
imageView, options);
return view;
}
......
이렇게 하면 모든 데이터 가 잘 맞 아 떨 어 집 니 다.그 다음 에 이미지 뷰 어 를 해 야 합 니 다.ListView 에서 Item 의'구 궁 격'-No Scroll Grid View 의 한 그림 을 클릭 할 때 이 그림 의 url 을 이미지 뷰 어 에 전송 해 야 합 니 다.이미지 뷰 어 에 전 달 된 url 에 따라 네트워크 에 이 그림 을 불 러 옵 니 다.그러면 사실 이미지 뷰 어 는 새로운 단독 Activity 입 니 다.이 Activity 는 하나의 ViewPager 를 포함 하여 여러 장의 그림 을 관리 하 는 데 사 용 됩 니 다.image_detail_pager.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.imagedemo.HackyViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black" />
<TextView
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@android:color/transparent"
android:gravity="center"
android:text="@string/viewpager_indicator"
android:textColor="@android:color/white"
android:textSize="18sp" />
</FrameLayout>
HackyViewPager.java
public class HackyViewPager extends ViewPager {
private static final String TAG = "HackyViewPager";
public HackyViewPager(Context context) {
super(context);
}
public HackyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException e) {
//
Log.e(TAG, "hacky viewpager error1");
return false;
} catch (ArrayIndexOutOfBoundsException e) {
//
Log.e(TAG, "hacky viewpager error2");
return false;
}
}
}
ImagePagerActivity.java
/**
*
*/
public class ImagePagerActivity extends FragmentActivity {
private static final String STATE_POSITION = "STATE_POSITION";
public static final String EXTRA_IMAGE_INDEX = "image_index";
public static final String EXTRA_IMAGE_URLS = "image_urls";
private HackyViewPager mPager;
private int pagerPosition;
private TextView indicator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image_detail_pager);
pagerPosition = getIntent().getIntExtra(EXTRA_IMAGE_INDEX, 0);
ArrayList<String> urls = getIntent().getStringArrayListExtra(
EXTRA_IMAGE_URLS);
mPager = (HackyViewPager) findViewById(R.id.pager);
ImagePagerAdapter mAdapter = new ImagePagerAdapter(
getSupportFragmentManager(), urls);
mPager.setAdapter(mAdapter);
indicator = (TextView) findViewById(R.id.indicator);
CharSequence text = getString(R.string.viewpager_indicator, 1, mPager
.getAdapter().getCount());
indicator.setText(text);
//
mPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int arg0) {
CharSequence text = getString(R.string.viewpager_indicator,
arg0 + 1, mPager.getAdapter().getCount());
indicator.setText(text);
}
});
if (savedInstanceState != null) {
pagerPosition = savedInstanceState.getInt(STATE_POSITION);
}
mPager.setCurrentItem(pagerPosition);
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(STATE_POSITION, mPager.getCurrentItem());
}
private class ImagePagerAdapter extends FragmentStatePagerAdapter {
public ArrayList<String> fileList;
public ImagePagerAdapter(FragmentManager fm, ArrayList<String> fileList) {
super(fm);
this.fileList = fileList;
}
@Override
public int getCount() {
return fileList == null ? 0 : fileList.size();
}
@Override
public Fragment getItem(int position) {
String url = fileList.get(position);
return ImageDetailFragment.newInstance(url);
}
}
}
이미 알 고 있 는 그림 보기 인 터 페 이 스 는 Fragment Activity 에서 계승 되 었 기 때문에 디 스 플레이 를 지원 하 는 인 터 페 이 스 는 Fragment 가 필요 합 니 다.Fragment 를 사용자 정의 하 십시오.이 Fragment 로 url 에서 그림 자원 을 가 져 와 그림 을 표시 합 니 다.image_detail_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black" >
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:contentDescription="@string/app_name"
android:scaleType="centerCrop" />
<ProgressBar
android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
</FrameLayout>
ImageDetailFragment.java
/**
* Fragment
*/
public class ImageDetailFragment extends Fragment {
private String mImageUrl;
private ImageView mImageView;
private ProgressBar progressBar;
private PhotoViewAttacher mAttacher;
public static ImageDetailFragment newInstance(String imageUrl) {
final ImageDetailFragment f = new ImageDetailFragment();
final Bundle args = new Bundle();
args.putString("url", imageUrl);
f.setArguments(args);
return f;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mImageUrl = getArguments() != null ? getArguments().getString("url")
: null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.image_detail_fragment,
container, false);
mImageView = (ImageView) v.findViewById(R.id.image);
mAttacher = new PhotoViewAttacher(mImageView);
mAttacher.setOnPhotoTapListener(new OnPhotoTapListener() {
@Override
public void onPhotoTap(View arg0, float arg1, float arg2) {
getActivity().finish();
}
});
progressBar = (ProgressBar) v.findViewById(R.id.loading);
return v;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ImageLoader.getInstance().displayImage(mImageUrl, mImageView,
new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
String message = null;
switch (failReason.getType()) {
case IO_ERROR:
message = " ";
break;
case DECODING_ERROR:
message = " ";
break;
case NETWORK_DENIED:
message = " , ";
break;
case OUT_OF_MEMORY:
message = " ";
break;
case UNKNOWN:
message = " ";
break;
}
Toast.makeText(getActivity(), message,
Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
}
@Override
public void onLoadingComplete(String imageUri, View view,
Bitmap loadedImage) {
progressBar.setVisibility(View.GONE);
mAttacher.update();
}
});
}
}
여기까지 쓰 고 이 박문 도 끝났다.제시 해 야 할 것 은 제 가 있 는 그림 뷰 어가 구현 한 그림 의 크기 조정 효 과 는 오픈 소스 구성 요소 인 PhotoView 를 사용 합 니 다.PhotoView 에 관 한 github 프로젝트 주 소 는 여기에 있 습 니 다.https://github.com/chrisbanes/PhotoView 이 프로젝트 의 사이트 주 소 를 눌 러 서 원본 코드 를 다운로드 하고 원본 코드 를 모두 프로젝트 에 복사 해 야 합 니 다.사용 도 상당히 편리 합 니 다.demo 는 다음 과 같 습 니 다.
ImageView mImageView;
PhotoViewAttacher mAttacher;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Any implementation of ImageView can be used!
mImageView = (ImageView) findViewById(R.id.iv_photo);
// Set the Drawable displayed
Drawable bitmap = getResources().getDrawable(R.drawable.wallpaper);
mImageView.setImageDrawable(bitmap);
// Attach a PhotoViewAttacher, which takes care of all of the zooming functionality.
mAttacher = new PhotoViewAttacher(mImageView);
}
// If you later call mImageView.setImageDrawable/setImageBitmap/setImageResource/etc then you just need to call
attacher.update();
처음에 이 이미지 뷰 어 는 제 가 사용자 정의 View 를 통 해 이 루어 진 것 입 니 다.사실은 이미지 의 제스처 인식+멀 티 터치+크기 조정 을 실현 해 야 합 니 다.행렬 Matrix 를 사용 하여 이 루어 질 수 있 습 니 다.다만 이렇게 하면 매우 번 거 로 워 보이 고 BUG 가 나타 나 기 쉽 습 니 다.이것 은 특정한'눈앞 의 이익 에 급급 한'프로젝트 에 있어 좋 지 않 은 징조 입 니 다.그래서 저 는 Matrix 로 사용자 정의 효 과 를 지양 하고 github 큰 소 가 저 희 를 위해 작성 한 오픈 소스 구성 요 소 를 사용 하면 효율 이 높 아 집 니 다.여러분 도 Matrix 로 그림 의 다 중 터치 확대 효 과 를 실현 할 수 있 습 니 다.Matrix 에 관 한 학습 은 예전 의 블 로그,Android 사용자 정의 컨트롤 인 3D 갤러리 와 이미지 행렬 에 참가 하 십시오.사실 안 드 로 이 드 의 그림 크기 조정 에 대해 서 는 다른 방법 이 없습니다.유일 하 게 사용 할 수 있 는 것 은 Matrix 입 니 다.믿 지 않 으 면 먼저 Github 황소 가 쓴 오픈 소스 구성 요소 인 PhotoView 가 어떻게 실현 되 는 지 보 세 요.다음 부분 소스 코드 를 보 세 요.
// These are set so we don't keep allocating them on the heap
private final Matrix mBaseMatrix = new Matrix();
private final Matrix mDrawMatrix = new Matrix();
private final Matrix mSuppMatrix = new Matrix();
private final RectF mDisplayRect = new RectF();
private final float[] mMatrixValues = new float[9];
/**
* Set's the ImageView's ScaleType to Matrix.
*/
private static void setImageViewScaleTypeMatrix(ImageView imageView) {
/**
* PhotoView sets it's own ScaleType to Matrix, then diverts all calls
* setScaleType to this.setScaleType automatically.
*/
if (null != imageView && !(imageView instanceof IPhotoView)) {
if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {
imageView.setScaleType(ScaleType.MATRIX);
}
}
}
이상 은 PhotoView 의 일부 소스 코드 일 뿐 입 니 다.한눈 에 알 수 있 듯 이 그의 실현 도 Matrix 의 시간 과 편폭 의 한계점 을 바탕 으로 합 니 다.여러분 들 이 PhotoView 의 실현 에 대해 더 잘 알 아야 한다 면 그 소스 코드 를 다운로드 하여 보 세 요.큰 신의 생각 을 이해 하려 면 튼튼한 기반 이 필요 합 니 다.PhotoView 의 구체 적 인 실현 디 테 일 에 대해 저도 잘 모 르 겠 습 니 다.제 가 Matrix 에 대해 잘 모 르 는 것 같 습 니 다.앞으로 공 부 를 강화 하고 앞으로 도 여러분 과 교류 하고 공부 하 며 함께 발전 하 기 를 바 랍 니 다!본문 전재:http://blog.csdn.net/allen315410/article/details/40264551
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.