Android custom RecyclerView achieves real Gallery effect, androidrecycler

Source: Internet
Author: User

Android custom RecyclerView achieves real Gallery effect, androidrecycler

Reprint please indicate the source: http://blog.csdn.net/lmj623565791/article/details/38173061, this article from:[Zhang Hongyang's blog]

In the previous blog, I used the custom HorizontalScrollView to write a horizontal image carousel With the HorizontalScrollView effect and ViewPager features. For details, see the custom Android HorizontalScrollView to create more images (controls) it is not afraid of the horizontal sliding effect of OOM. In fact, the other control that has to be used for horizontal scrolling is the newly added RecyclerView by Google. It is said that it is an upgraded version of ListView. This blog first introduces the usage of RecyclerView, then, perform some analysis. Finally, customize the RecyclerView to achieve the desired album effect.

1. Basic usage of RecyclerView

First, the layout file of the main Activity:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <android.support.v7.widget.RecyclerView        android:id="@+id/id_recyclerview_horizontal"        android:layout_width="match_parent"        android:layout_height="120dp"        android:layout_centerVertical="true"        android:background="#FF0000"        android:scrollbars="none" /></RelativeLayout>

Item layout file:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="120dp"    android:layout_height="120dp"    android:background="@drawable/item_bg02" >    <ImageView        android:id="@+id/id_index_gallery_item_image"        android:layout_width="80dp"        android:layout_height="80dp"        android:layout_alignParentTop="true"        android:layout_centerHorizontal="true"        android:layout_margin="5dp"        android:scaleType="centerCrop" />    <TextView        android:id="@+id/id_index_gallery_item_text"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/id_index_gallery_item_image"        android:layout_centerHorizontal="true"        android:layout_marginBottom="5dp"        android:layout_marginTop="5dp"        android:textColor="#ff0000"        android:text="some info"        android:textSize="12dp" /></RelativeLayout>

Data adapter:

Package com. example. zhy_horizontalscrollview03; import java. util. list; import android. content. context; import android. support. v7.widget. recyclerView; import android. view. layoutInflater; import android. view. view; import android. view. viewGroup; import android. widget. imageView; import android. widget. textView; public class GalleryAdapter extendsRecyclerView. adapter <GalleryAdapter. viewHolder> {private LayoutInflater mInflater; private List <Integer> mDatas; public GalleryAdapter (Context context, List <Integer> datats) {mInflater = LayoutInflater. from (context); mDatas = datats;} public static class ViewHolder extends RecyclerView. viewHolder {public ViewHolder (View arg0) {super (arg0) ;}imageview mImg; TextView mTxt ;}@ Overridepublic int getItemCount () {return mDatas. size ();}/*** create ViewHolder */@ Overridepublic ViewHolder onCreateViewHolder (ViewGroup viewGroup, int I) {View view = mInflater. inflate (R. layout. activity_index_gallery_item, viewGroup, false); ViewHolder viewHolder = new ViewHolder (view); viewHolder. mImg = (ImageView) view. findViewById (R. id. id_index_gallery_item_image); return viewHolder;}/*** set value */@ Overridepublic void onBindViewHolder (final ViewHolder viewHolder, final int I) {viewHolder. mImg. setImageResource (mDatas. get (I ));}}

We can see that the comparison between the data adapter and BaseAdapter has undergone considerable changes. There are three main methods:

GetItemCount needless to say, get the total number of entries

OnCreateViewHolder create ViewHolder

OnBindViewHolder binds data to ViewHolder

It can be seen that RecyclerView also encapsulates ViewHolder, But if you observe it carefully, you will have a question: the ListView contains a getView that returns the layout of the View as an Item, so where can this Item be controlled?

In fact, the ViewHolder we created must inherit the RecyclerView. viewHolder, this RecyclerView. when constructing ViewHolder, you must input a View. This View is equivalent to convertView in our ListView getView (that is, we need to input the inflate item layout ).

Another point is that convertView in ListView is reused. In RecyclerView, ViewHolder is used as the cache unit, and convertView is used as a member variable of ViewHolder in ViewHolder. That is to say, if 10 entries are not displayed on the screen, 10 ViewHolder files are created and cached. ViewHolder is reused each time. Therefore, the getView method is changed to onCreateViewHolder. If you are interested, print the Log and test it.

Finally, use the following in Activity:

Package com. example. zhy_horizontalscrollview03; import java. util. arrayList; import java. util. arrays; import java. util. list; import android. app. activity; import android. OS. bundle; import android. support. v7.widget. linearLayoutManager; import android. support. v7.widget. recyclerView; import android. view. window; public class MainActivity extends Activity {private RecyclerView mRecyclerView; private GalleryAdapter mAdapter; private List <Integer> mDatas; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); requestWindowFeature (Window. FEATURE_NO_TITLE); setContentView (R. layout. activity_main); initDatas (); // obtain the control mRecyclerView = (RecyclerView) findViewById (R. id. id_recyclerview_horizontal); // sets the layout manager LinearLayoutManager linearLayoutManager = new LinearLayoutManager (this); linearLayoutManager. setOrientation (LinearLayoutManager. HORIZONTAL); mRecyclerView. setLayoutManager (linearLayoutManager); // set the adapter mAdapter = new GalleryAdapter (this, mDatas); mRecyclerView. setAdapter (mAdapter);} private void initDatas () {mDatas = new ArrayList <Integer> (Arrays. asList (R. drawable. a, R. drawable. b, R. drawable. c, R. drawable. d, R. drawable. e, R. drawable. f, R. drawable. g, R. drawable. h, R. drawable. l ));}}

LayoutManager is easy to use. Currently, only one implementation class is LinearLayoutManager, which can be set to horizontal or vertical.

Finally:


This is the basic usage of RecyclerView, but you will find that the callback of setOnItemClickListener is not provided...

2. Add OnItemClickListener callback for RecyclerView

Although it is not provided, adding an OnItemClickListener is not a piece of cake for us ~

I decided to add this callback interface to the Adapter:

Package com. example. zhy_horizontalscrollview03; import java. util. list; import android. content. context; import android. support. v7.widget. recyclerView; import android. view. layoutInflater; import android. view. view; import android. view. view. onClickListener; import android. view. viewGroup; import android. widget. imageView; import android. widget. textView; public class GalleryAdapter extendsRecyclerView. adapter <Galle RyAdapter. viewHolder> {/*** ItemClick callback interface * @ author zhy **/public interface OnItemClickLitener {void onItemClick (View view, int position);} private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener (OnItemClickLitener mOnItemClickLitener) {this. mOnItemClickLitener = mOnItemClickLitener;} private LayoutInflater mInflater; private List <Integer> mDatas; public GalleryAdapter (Context Context, List <Integer> datats) {mInflater = LayoutInflater. from (context); mDatas = datats;} public static class ViewHolder extends RecyclerView. viewHolder {public ViewHolder (View arg0) {super (arg0) ;}imageview mImg; TextView mTxt ;}@ Overridepublic int getItemCount () {return mDatas. size () ;}@ Overridepublic ViewHolder onCreateViewHolder (ViewGroup viewGroup, int I) {View view = mInflater. inflate (R. layout. activ Ity_index_gallery_item, viewGroup, false); ViewHolder viewHolder = new ViewHolder (view); viewHolder. mImg = (ImageView) view. findViewById (R. id. id_index_gallery_item_image); return viewHolder ;}@ Overridepublic void onBindViewHolder (final ViewHolder viewHolder, final int I) {viewHolder. mImg. setImageResource (mDatas. get (I); // if callback is set, set the click event if (mOnItemClickLitener! = Null) {viewHolder. itemView. setOnClickListener (new OnClickListener () {@ Overridepublic void onClick (View v) {mOnItemClickLitener. onItemClick (viewHolder. itemView, I );}});}}}

It is easy to create an interface, provide a setting entry, and then judge in onBindViewHolder.

Finally, set the listener in the main Activity:

mAdapter = new GalleryAdapter(this, mDatas);mAdapter.setOnItemClickLitener(new OnItemClickLitener(){@Overridepublic void onItemClick(View view, int position){Toast.makeText(MainActivity.this, position+"", Toast.LENGTH_SHORT).show();}});mRecyclerView.setAdapter(mAdapter);

Okay, that's all. Let's see:


The effect is good. Next I want to change it to the album effect, that is, a large image is displayed, and the RecyclerView below is used as the indicator for picture switching.

3. Custom RecyclerView for content interaction during scrolling

First, modify the layout:

Layout file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <FrameLayout        android:layout_width="fill_parent"        android:layout_height="0dp"        android:layout_weight="1" >        <ImageView            android:id="@+id/id_content"            android:layout_width="fill_parent"            android:layout_height="fill_parent"            android:layout_gravity="center"            android:layout_margin="10dp"            android:scaleType="centerCrop"            android:src="@drawable/ic_launcher" />    </FrameLayout>    <com.example.zhy_horizontalscrollview03.MyRecyclerView        android:id="@+id/id_recyclerview_horizontal"        android:layout_width="match_parent"        android:layout_height="120dp"        android:layout_gravity="bottom"        android:background="#FF0000"        android:scrollbars="none" /></LinearLayout>

Add a region for displaying a large image and change the RecyclerView to its own definition.

Then let's look at our custom RecyclerView code:

Package com. example. zhy_horizontalscrollview03; import android. content. context; import android. support. v7.widget. recyclerView; import android. util. attributeSet; import android. view. motionEvent; import android. view. view; public class CopyOfMyRecyclerView extends RecyclerView {public CopyOfMyRecyclerView (Context context, AttributeSet attrs) {super (context, attrs);} private View mCurrentView; /*** callback interface during scrolling */p Rivate OnItemScrollChangeListener mItemScrollChangeListener; public void setOnItemScrollChangeListener (OnItemScrollChangeListener mItemScrollChangeListener) {this. listener = mItemScrollChangeListener;} public interface OnItemScrollChangeListener {void onChange (View view, int position);} @ Overrideprotected void onLayout (boolean changed, int l, int t, int r, int B) {super. onLayout (changed, L, t, r, B); mCurrentView = getChildAt (0); if (mItemScrollChangeListener! = Null) {mItemScrollChangeListener. onChange (mCurrentView, getChildPosition (mCurrentView) ;}@ Overridepublic boolean onTouchEvent (MotionEvent e) {if (e. getAction () = MotionEvent. ACTION_MOVE) {mCurrentView = getChildAt (0); // Log. e ("TAG", getChildPosition (getChildAt (0) + ""); if (mItemScrollChangeListener! = Null) {mItemScrollChangeListener. onChange (mCurrentView, getChildPosition (mCurrentView) ;}return super. onTouchEvent (e );}}

Defines an interface for callback during scrolling, and listens to ACTION_MOVE in onTouchEvent. When the user's fingers slide, the current first View is continuously called back ~

How do I know that getChildAt (0) and getChildPosition () are available? At first I thought there was the getFirstVisibleItem method, and then I found it; but I found getRecycledViewPool () I think the name is the cache queue of Viewholder. If I want to directly retrieve the first queue, isn't it the View I want? I didn't succeed. I observed its internal View, and finally found that the first display is always its first child. As for the getChildPosition method, I can see it.

Current results:



The effect is the same as that in my previous example. However, I still want to make some changes. I think the Gallery or album indicator may contain 1000 images below, not only do I like to slide my fingers on the screen, but the image will automatically switch over. I also hope that if I give the indicator an acceleration, even if the finger leaves and the bottom is still sliding, the above will be linked. In addition, I want to make some optimizations and directly call back in ACTION_MOVE. The trigger frequency is too high. In theory, an image will only be triggered once ~~

4. Optimize and create a real Gallery Effect

Now that you want to interact with your fingers, you need to listen not only to ACTION_MOVE, but also to listen to acceleration. The speed reaches a certain value and then move on ~~ Let's try again. Is it so troublesome? Isn't it possible to scroll? So there should be OnScrollListener. Let's just look at it. It really does. Hahaha ~ The modified code is as follows:

Package com. example. zhy_horizontalscrollview03; import android. content. context; import android. support. v7.widget. recyclerView; import android. support. v7.widget. recyclerView. onScrollListener; import android. util. attributeSet; import android. view. view; public class MyRecyclerView extends RecyclerView implements OnScrollListener {/*** record the current first View */private View mCurrentView; private OnItemScrollChangeListene R mItemScrollChangeListener; public void setOnItemScrollChangeListener (OnItemScrollChangeListener mItemScrollChangeListener) {this. listener = mItemScrollChangeListener;} public interface OnItemScrollChangeListener {void onChange (View view, int position);} public MyRecyclerView (Context context, AttributeSet attrs) {super (context, attrs ); // TODO Auto-generated constructor stubthis. setOnSc RollListener (this) ;}@ Overrideprotected void onLayout (boolean changed, int l, int t, int r, int B) {super. onLayout (changed, l, t, r, B); mCurrentView = getChildAt (0); if (mItemScrollChangeListener! = Null) {mItemScrollChangeListener. onChange (mCurrentView, getChildPosition (mCurrentView) ;}@ Overridepublic void onScrollStateChanged (int arg0) {}/ *** determines whether the current first View has changed, callback only when a callback occurs */@ Overridepublic void onScrolled (int arg0, int arg1) {View newView = getChildAt (0); if (mItemScrollChangeListener! = Null) {if (newView! = Null & newView! = MCurrentView) {mCurrentView = newView; mItemScrollChangeListener. onChange (mCurrentView, getChildPosition (mCurrentView ));}}}}

I gave up rewriting the onTouchEvent method, but used this class to implement the RecyclerView. OnScrollListener interface, set the listener, and judge in onScrolled.

Optimization: I used a member change to store the current first View. Only when the first View changes will the callback be made ~~ It's perfect ~

Look at MainActivity:

package com.example.zhy_horizontalscrollview03;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.view.Window;import android.widget.ImageView;import android.widget.Toast;import com.example.zhy_horizontalscrollview03.GalleryAdapter.OnItemClickLitener;import com.example.zhy_horizontalscrollview03.MyRecyclerView.OnItemScrollChangeListener;public class MainActivity extends Activity{private MyRecyclerView mRecyclerView;private GalleryAdapter mAdapter;private List<Integer> mDatas;private ImageView mImg ; @Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);mImg = (ImageView) findViewById(R.id.id_content);mDatas = new ArrayList<Integer>(Arrays.asList(R.drawable.a,R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.e,R.drawable.f, R.drawable.g, R.drawable.h, R.drawable.l));mRecyclerView = (MyRecyclerView) findViewById(R.id.id_recyclerview_horizontal);LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);mRecyclerView.setLayoutManager(linearLayoutManager);mAdapter = new GalleryAdapter(this, mDatas);mRecyclerView.setAdapter(mAdapter);mRecyclerView.setOnItemScrollChangeListener(new OnItemScrollChangeListener(){@Overridepublic void onChange(View view, int position){mImg.setImageResource(mDatas.get(position));};});mAdapter.setOnItemClickLitener(new OnItemClickLitener(){@Overridepublic void onItemClick(View view, int position){//Toast.makeText(getApplicationContext(), position + "", Toast.LENGTH_SHORT)//.show();mImg.setImageResource(mDatas.get(position));}});}}

The Code remains unchanged ~ Callback with more settings ~

:


We can see that not only does the mobile phone support changes when moving above, but if I give an acceleration, the following will continue to roll and the above will also continue to change ~~ Thumb UPS ~ Each image is called back once, and the efficiency is quite good.


Now, after reading this blog, I believe you have some knowledge about RecyclerView, and even have a better understanding of how to transform a control ~~


If you think it is good, leave a comment or give a thumbs up to show support for me.


Download source code




How does android gallery achieve linkage results?

Gallery gallery = (Gallery) findViewById (R. id. gallery );
// Specify an adapter for the thumbnail Browser
Gallery. setAdapter (new ImageAdapter (this ));
// Response to the event after a thumbnail is selected on the thumbnail list
Gallery. setOnItemSelectedListener (new AdapterView. OnItemSelectedListener (){
@ Override
Public void onItemSelected (AdapterView <?> Parent, View v,
Int position, long id ){
Toast. makeText (_ Gallery. this, String. valueOf (position), Toast. LENGTH_SHORT). show ();
}

@ Override
Public void onNothingSelected (AdapterView <?> Arg0 ){

}
});
}

// Inherit the BaseAdapter for custom image adapters
Public class ImageAdapter extends BaseAdapter {

Private Context mContext;

Public ImageAdapter (Context context ){
MContext = context;
}

Public int getCount (){
Return mThumbIds. length;
}

Public Object getItem (int position ){
Return position;
}

Public long getItemId (int position ){
Return position;
}

Public View getView (int position, View convertView, ViewGroup parent ){
ImageView image = new ImageView (mContext );

Image. setImageResource (mThumbIds [position]);
Image. setAdjustViewBounds (true );
Image. setLayoutParams (new Gallery. LayoutParams (
LayoutParams. WRAP_CONTENT, LayoutParams. WRAP_CONTENT) ...... the remaining full text>

Android Gallery can contain controls other than ImageView.

For any view, you can customize the view and use the adapter to inject your own view with inflate, and each item of Gallery will display your view, your view can be a simple ImageView or a complicated layout, depending on how you use it. The key is that you have to deal with the adapter. There are many examples of adapter on the Internet.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.