Before reading the article, I hope you open their own micro-letter point to the circle of friends, carefully observed is not found in the circle of friends have a "nine Sudoku" Picture area, click on the picture will jump to the picture of the Detailed view page, and support the slide and zoom image? This function is not very commonly used?! So I happen to do this demo today, the following for you to explain. First of all, follow the convention first look at the effect of the picture bar, especially do not record GIF animation (ah ~ No way, simulator does not support multi-touch, just my mobile phone and no root, can not record screen, sad reminders Ah, we forgive, want to see the real effect of words, please move to the bottom of the article reproduced in the source code download, click Download Source Code, After the operation to see the effect of Kazakhstan ~ ~), here first take a few static pictures to replace a good one. Excuse me!
Effect, will look at it! Really do not understand to think about micro-trust friends Circle, or drag to the bottom, click Download Source! Here, first analysis of the main interface bar, the layout is very simple, the main interface is just a ListView control, ListView item is worth noting that the item contains a GridView, this GridView used to achieve the "nine Sudoku" effect, The main interface layout is a ListView, here do not say, we first look at the ListView item layout bar, the following is Item_list.xml
<!--?</span--> The XML version = "1.0" encoding = "utf-8"? >
The < RelativeLayout XMLNS: android = "http://schemas.android.com/apk/res/android"
Android: layout_width = "match_parent"
Android: layout_height = "match_parent"
Android: paddingBottom = "5 dp"
Android: paddingTop = "5 dp" >
The < ImageView
The android: id = "@ + id/iv_avatar"
Android: layout_width = "50 dp"
Android: layout_height = "50 dp"
Android: background = "@ drawable/ic_launcher"
Android: scaleType = "centerCrop" / >
The < TextView
The android: id = "@ + id/tv_title"
Android: layout_width = "wrap_content"
Android: layout_height = "wrap_content"
Android: layout_marginLeft = "5 dp"
Android: layout_toRightOf = "@ id/iv_avatar"
Android :text=" I'm in a good mood today!"
Sp android: textSize = "16" / >
The < TextView
The android: id = "@ + id/tv_content"
Android: layout_width = "wrap_content"
Android: layout_height = "wrap_content"
Android: layout_below = "@ + id/tv_title"
Android: layout_marginLeft = "5 dp"
Android: layout_marginTop = "3 dp"
Android: layout_toRightOf = "@ id/iv_avatar"
Android :text=" smog again today!"
Sp android: textSize = "16" / >
The < com. Example. Imagedemo NoScrollGridView
The android: id = "@ + id/gridview"
Android: layout_width = "220 dp"
Android: layout_height = "wrap_content"
Android: layout_below = "@ id/tv_content"
Android: layout_marginLeft = "5 dp"
Android: layout_marginTop = "3 dp"
Android: layout_toRightOf = "@ id/iv_avatar"
Android: columnWidth = "70 dp"
Android: gravity = "center"
Android: horizontalSpacing = "2.5 dp"
Android: numColumns = "3"
Android: stretchMode = "columnWidth"
2.5 dp android: verticalSpacing = "" / >
< / RelativeLayout >
Well, as you can see, the layout is extremely simple, but one problem is that ListView is nested into the GridView, and then there's a problem. Causes the GridView to display incomplete, how should we solve this problem? In fact, it is also simple to rewrite a GridView, measure the height of the GridView, and then set up. Specific solutions please see the blog listview nested GridView shows incomplete workaround or source code, as follows Noscrollgridview.java
Package com. Example. Imagedemo;
The import android. The content. The Context;
The import android. Util. AttributeSet;
The import android. Widget. The GridView;
/ * *
* custom "nine-grid" - used to solve a problem in the image collection that displays the details of posts: the GridView is not fully displayed, only a one-line image is displayed
*
* @ author lichao
* @ 16:41 since 2014-10-16
*
* /
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, 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);
}
}
The next step is to look at the data structure of the entity on the ListView item above, which is very simple.
public class Itementity {
private string avatar//user avatar URL
private string title;//title
private string content ; Content
Private arraylist<string> imageurls//Nine the URL collection for the picture is public
itementity (string avatar, string title, String content,
arraylist<string> imageurls) {
super ();
This.avatar = Avatar;
this.title = title;
this.content = content;
This.imageurls = Imageurls;
}
...
}
Well, with the ListView, then the inevitable thing is to do the data on the item is fit. Inherit a baseadapter, the code is as follows, are relatively simple:
/ * *
* data adapter for the home page ListView
*
* @ author Administrator
*
* /
Public class ListItemAdapter extends BaseAdapter {
Private Context mContext;
Private ArrayList < ItemEntity > items;
Public ListItemAdapter(Context CTX, ArrayList<itementity> items) {</itementity>
Enclosing mContext = CTX;
Enclosing the items = items;
}
@ Override
Public int getCount () {
Return items == null? Zero: the items. The size ();
}
@ Override
Public Object getItem(int position) {
Return the items. The get (position);
}
@ Override
Public long getItemId(int position) {
Return the position;
}
@ Override
Public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
If (convertView == null) {
Holder = new ViewHolder ();
ConvertView = the inflate (mContext, R.l ayout. Item_list, null);
ConvertView holder. Iv_avatar = (ImageView)
The findViewById (R.i d.i v_avatar);
ConvertView holder. Tv_title = (TextView)
The findViewById (R.i which v_title);
ConvertView holder. Tv_content = (TextView)
The findViewById (R.i which v_content);
Holder. The gridview = (NoScrollGridView) convertView
The findViewById (R.i d.g ridview);
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 ());
// load network images using ImageLoader
DisplayImageOptions options = new DisplayImageOptions. Builder () / /
. ShowImageOnLoading (r.rawable.ic_launcher) // default image displayed in load
. ShowImageOnFail (r.rawable.ic_launcher) // sets the default image that failed to load
.cacheinmemory (true) // memory cache
.cacheondisk (true) // sdcard cache
.bitmapconfig (config.rgb_565)// sets the minimum configuration
The build (); //
ImageLoader. GetInstance (). The displayImage (itemEntity getAvatar (),
Holder iv_avatar, options);
Final ArrayList<string> imageUrls = itementity.getimageurls ();</string>
If (imageUrls == null || imageurls.size () == 0) {// hide GridView without image resources
Holder. The gridview. SetVisibility (View. GONE);
} else {
Holder. The gridview. SetAdapter (new NoScrollGridAdapter (mContext,
ImageUrls));
}
// click the return card to see a larger picture
Holder. The gridview. SetOnItemClickListener (new OnItemClickListener () {
@ Override
Public void onItemClick (AdapterView <!--?</span--> > the parent, View View,
Int position, long id) {
// TODO auto-generated method stub
ImageBrower (position, imageUrls);
}
});
Return convertView.
}
/ * *
* open the image viewer
*
* @ param position
* @ param urls2
* /
Protected void imageBrower(int position, ArrayList<string> urls2) {</string>
Intent Intent = new Intent(mContext, imagepageractivity.class);
// image url, to demonstrate the use of constants here, is usually obtained from a database or network
Intent. PutExtra (ImagePagerActivity EXTRA_IMAGE_URLS, urls2);
Intent. PutExtra (ImagePagerActivity EXTRA_IMAGE_INDEX, position);
MContext. StartActivity (intent);
}
/ * *
* listview components are reused to prevent "jam"
*
* @ author Administrator
*
* /
The class ViewHolder {
Private ImageView iv_avatar;
Private TextView tv_title;
Private TextView tv_content;
Private NoScrollGridView gridview.
}
}
There is a need to explain the place, look at the ListView on the image processing, because the pictures are obtained from the network, in order to avoid excessive image caused by oom, Then loading pictures here when necessary to do memory optimization, picture optimization way There are many, I have taken the simplest and most direct way, using the open source Imageloader This picture loading framework, this framework is simply too excellent, Reduces the developer a series of unnecessary and often have trouble, regarding Imageloader is not the knowledge which this article needs to explain, regarding Imageloader, welcome to download on the GitHub homepage, the address is https://github.com/ Nostra13/android-universal-image-loader , now that you use the Imageloader framework, you have to do some initialization on the program, First of all, you need to customize a global context application class, the Imageloader related to initialize the relevant properties, directly look at the code well, see the name known: Myapplication.java
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)//Cache 100 pictures. Writedebuglogs ()//. Build ();//Imageloader.getinstance (). init (config); }
}
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);
}
}
After defining this application, you need to configure it in the manifest file and add it to the application node in manifest.xml:
android:name= "Com.example.imagedemo.MyApplication"
in addition, because Imageloader is the network to obtain the picture, but also needs the local SDcard cache picture, therefore needs to add the permission, this is the Imageloader standard permission:
<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" />
Then look at the above item data, there is a GridView, obviously this GridView also need to do data adaptation, this data response is to load pictures from the network, relatively simple, see Code Noscrollgridadapter.java
......
Override public
View getview (int position, View Convertview, ViewGroup parent) {
View view = View.inflate (CTX, R.L Ayout.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;
}
......
In this way, all the data adaptation is done, the next need to do picture Viewer, when we click on the item in the "Nine Sudoku"--noscrollgridview of a picture, you need to listview this picture URL to a picture viewer, The image Viewer will load the image according to the URL passed in, so the picture viewer is a new individual activity that contains a viewpager that manages the viewing of multiple images. 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 {
super (context);
}
Public Hackyviewpager (context, AttributeSet attrs) {
Super (context, attrs);
}
@Override Public
Boolean onintercepttouchevent (motionevent ev) {
try {
return Super.onintercepttouchevent (EV);
} catch (IllegalArgumentException e) {
//Ignore
LOG.E (TAG, "Hacky viewpager error1");
return false;
} catch (ArrayIndexOutOfBoundsException e) {
//Ignore
LOG.E (TAG, "Hacky viewpager Error2");
return false;}}
Imagepageractivity.java
/** * Picture Viewer */public class Imagepageractivity extends Fragmentactivity {private static final String State_positi
on = "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); Update subscript Mpager.setonpagechangelistener (new Onpagechangelistener () {@Override public void Onpagescrollstatechang
Ed (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.getcurrentit
EM ());
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);
}
}
}
Known picture view of the interface is inherited from the fragmentactivity, so support the display of the interface must be fragment to achieve, then customize a frangment bar, with this fragment to get picture resources from the URL, display pictures. 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
/** * Single picture shows 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 (NewOnphototaplistener () {@Override public void Onphototap (View arg0, float arg1, float arg2) {getactivity (). Fini
SH ();
}
});
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 Publ
IC void onloadingstarted (String imageuri, view view) {progressbar.setvisibility (view.visible); @Override public void onloadingfailed (string imageuri, view view, Failreason Failreason) {string mes
Sage = null;
Switch (Failreason.gettype ()) {Case io_error:message = "Download Error";
Break
Case decoding_error:message = "picture cannot show";
Break
Case network_denied:message = "Network has problems, can not download";
Break
Case out_of_memory:message = "picture too big to show";
Break Case UnknowN:message = "Unknown error";
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 ();
}
});
}
}
writing here, this blog post is over. What needs to be proposed is that my picture viewer here implements the zoom effect of the image to use the open Source component Photoview, about Photoview's GitHub project address here, https://github.com/chrisbanes/ Photoview need to point to the URL of this project, to download the source code, the source code all copied to the project, the use is quite convenient, the demo is as follows:
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 are later call Mimageview.setimagedrawable/setimagebitmap/setimageresource/etc then your just need to call at
Tacher.update ();
The first picture viewer is my own custom view to implement, in fact, the need to achieve the image of gesture recognition + multi-touch + zoom, can be achieved using matrix matrices, but this is particularly troublesome not to say, and very easy to appear bugs, this for some "quick success" of the project, It's a bad omen. So, I have abandoned my use of the matrix custom effect, instead of GitHub Daniel for our open source components, so that efficiency went up, we can also use the matrix to achieve the image of the multi-touch zoom effect, on the matrix of learning, please join my previous blog, Android Custom Control--3d gallery and image matrix. In fact, on the Android picture scaling really no other way, the only use of the Matrix this class, do not believe first to see GitHub Daniel wrote the open source component Photoview How to achieve, view the following parts of the source code:
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);}}}
The above is just photoview part of the source code, at a glance found that its implementation is also based on the matrix, Time and space limitations, we need to better understand the implementation of Photoview, download its source view it, to understand the idea of great God is to need some solid foundation, On the specific implementation of Photoview details, I also do not understand, may be I understand the matrix is not deep, I hope to strengthen learning, but also hope to communicate with you to learn, common progress!
Reproduced in this article: http://blog.csdn.net/allen315410/article/details/40264551