Related
I know that there are countless examples of this on the internet, but for some reason I can't get this to work in the particular code I'm working on, despite all the resources/answers I've read through. And I don't have anyone with Java skills around me to help out. So hopefully that changes here.
I'm updating an existing Android media picker plugin (for a cordova app) to make it show video thumbnails in addition to pictures in the device gallery. I'm stuck with a "non-static variable in static context" error, but I'm having a really hard time identifying what needs to be changed. Below is the meat of the code I have. I have removed some parts to hopefully focus on the relevant bits. Essentially, the error occurs inside decodeSampledBitmapFromUri when I'm trying to get the thumbnail of a video. The method I'm using is MediaStore.Video.Thumbnails.getThumbnail and its first argument is the context, which is where the error starts. You can see that in loadThumbnail I tried getting the context using cordova.getActivity() and then passing it to decodeSampledBitmapFromUri, but even inside loadThumbnail I'm still getting the non-static error. I'm not sure how to proceed from here (I'm very new to Java). This is the code (with some other parts stripped out because I think they're not relevant):
public class MediaPicker extends CordovaPlugin {
private static final String HEIGHT = "height";
private static final String COLUMNS = "columns";
private static final String SELECTION_LIMIT = "selectionLimit";
private MediaPickerView view;
public static int getResourceId(Context context, String group, String key) {
return context.getResources().getIdentifier(key, group, context.getPackageName());
}
public static int DP2PX(Context context, float dipValue) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics);
}
#Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
}
#Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
if (action.equals("display")) {
JSONObject store = data.getJSONObject(0);
double height = Double.parseDouble(store.getString(HEIGHT));
int columns = Integer.parseInt(store.getString(COLUMNS));
int selectionLimit = Integer.parseInt(store.getString(SELECTION_LIMIT));
display(height, columns, selectionLimit, callbackContext);
return true;
} else {
return false;
}
}
private void display(final double height, final int columns, final int selectionLimit, final CallbackContext callbackContext) {
cordova.getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (view == null) {
view = new MediaPickerView(cordova.getActivity());
}
view.setOptions(height, columns, selectionLimit, callbackContext);
view.load();
cordova.getActivity().addContentView(view,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
}
});
}
public static class MediaPickerView extends FrameLayout implements StateController {
private GridView grid;
private View balanceView;
private int selectionLimit;
private CallbackContext callbackContext;
private TreeMap<Integer, PictureInfo> selection = new TreeMap();
public MediaPickerView(Context context) {
super(context);
init();
}
public MediaPickerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
LayoutInflater.from(getContext()).inflate(getResourceId(getContext(), "layout", "view_media"), this);
grid = (GridView)findViewById(getResourceId(getContext(), "id", "gridView"));
balanceView = findViewById(getResourceId(getContext(), "id", "vBalancer"));
}
public void setOptions(double height, int columns, int selectionLimit, CallbackContext callbackContext) {
this.selectionLimit = selectionLimit;
this.callbackContext = callbackContext;
grid.setNumColumns(columns);
LinearLayout.LayoutParams glp = (LinearLayout.LayoutParams) grid.getLayoutParams();
glp.weight = (float) height;
LinearLayout.LayoutParams blp = (LinearLayout.LayoutParams) balanceView.getLayoutParams();
blp.weight = (float) (1 - height);
requestLayout();
}
public void load() {
final GridAdapter adapter = new GridAdapter(getContext(), this);
grid.setAdapter(adapter);
new Thread() {
#Override
public void run() {
final String[] columns = new String[]{
MediaStore.Video.VideoColumns._ID,
MediaStore.Video.VideoColumns.DATA,
MediaStore.Video.VideoColumns.BUCKET_DISPLAY_NAME,
MediaStore.Video.VideoColumns.DISPLAY_NAME,
MediaStore.Video.VideoColumns.DATE_TAKEN,
MediaStore.Video.VideoColumns.MIME_TYPE,
MediaStore.Files.FileColumns.MEDIA_TYPE};
final String orderBy = MediaStore.Video.VideoColumns.DATE_TAKEN
+ " DESC";
final String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;
Uri queryUri = MediaStore.Files.getContentUri("external");
final Cursor cursor = getContext().getContentResolver().query(
queryUri,
columns,
selection, // Which rows to return (all rows)
null, // Selection arguments (none)
orderBy);
if (cursor.moveToFirst()) {
adapter.setCursor(cursor);
}
}
}.start();
}
}
public static class MediaCache extends LruCache<String, Bitmap> {
public MediaCache(int maxSize) {
super(maxSize);
}
#Override
protected int sizeOf(String key, Bitmap value) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
return value.getAllocationByteCount();
}
return value.getByteCount();
}
}
public static class GridAdapter extends BaseAdapter implements AsyncPictureLoader{
private Cursor cursor;
private Executor executor = Executors.newFixedThreadPool(4);
private MediaCache pictureCache;
private int dataColumn;
private StateController stateController;
private ArrayList<PictureView> createdViews = new ArrayList<PictureView>();
public GridAdapter(Context context, StateController stateController) {
this.stateController = stateController;
int memClass = ( (ActivityManager)context.getSystemService( Context.ACTIVITY_SERVICE ) ).getMemoryClass();
int cacheSize = 1024 * 1024 * memClass / 10;
pictureCache = new MediaCache(cacheSize);
}
#Override
public int getCount() {
return cursor != null ? cursor.getCount() : 0;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
PictureView view;
if (convertView != null) {
view = (PictureView) convertView;
} else {
view = new PictureView(pictureCache, parent.getContext(), this, stateController);
createdViews.add(view);
}
view.load(position);
return view;
}
public void setCursor(Cursor cursor) {
this.cursor = cursor;
dataColumn = cursor
.getColumnIndex(MediaStore.Video.VideoColumns.DATA);
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
});
}
#Override
public void loadThumbnail(final PictureInfo pictureInfo, final AsyncPictureLoaderCallback callback) {
if (cursor == null) {
return;
}
executor.execute(new Runnable() {
#Override
public void run() {
if (cursor == null || pictureInfo.cancelled) {
return;
}
synchronized (cursor) {
cursor.moveToPosition(pictureInfo.position);
pictureInfo.uri = cursor.getString(dataColumn);
}
if (pictureInfo.uri == null) {
return;
}
synchronized (pictureCache) {
Bitmap cachedBitmap = pictureCache.get(pictureInfo.uri);
if (cachedBitmap != null) {
pictureInfo.thumbnail = cachedBitmap;
callback.onLoad(pictureInfo);
return;
}
}
int thumbSideSize = callback.getThumbnailSideSize();
if (thumbSideSize <= 0) {
thumbSideSize = 128;
}
// the next 4 variables are needed for videos, see https://stackoverflow.com/a/29555484/7987987
int type = cursor.getColumnIndex(MediaStore.Files.FileColumns.MEDIA_TYPE);
int tInt = cursor.getInt(type);
int colId = cursor.getColumnIndex(MediaStore.Video.VideoColumns._ID);
int id = cursor.getInt(colId);
pictureInfo.thumbnail = decodeSampledBitmapFromUri(pictureInfo.uri, thumbSideSize, thumbSideSize, tInt, id, cordova.getActivity());
if (pictureInfo.thumbnail != null) {
callback.onLoad(pictureInfo);
synchronized (pictureCache) {
pictureCache.put(pictureInfo.uri, pictureInfo.thumbnail);
}
} else {
}
}
});
}
private Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight, int typeInt, int id, Context context) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
if (typeInt == 3) {
// this is a video, handle according to https://stackoverflow.com/a/29555484/7987987
// using BitmapFactory options as seen in the link above
options.inSampleSize = 4; // hardcoded for now until this works, then I'll make it dynamic
options.inPurgeable = true;
bm = MediaStore.Video.Thumbnails.getThumbnail(
context.getContentResolver(), id,
MediaStore.Video.Thumbnails.MINI_KIND, options);
} else {
// this is an image
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);
}
return bm;
}
public int calculateSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
}
public interface AsyncPictureLoader {
void loadThumbnail(PictureInfo position, AsyncPictureLoaderCallback callback);
}
public interface AsyncPictureLoaderCallback {
void onLoad(PictureInfo picture);
int getThumbnailSideSize();
}
public interface StateController {
// stuff here that controls selection
}
public static class PictureInfo {
public int position;
public String uri;
public Bitmap thumbnail;
public volatile boolean cancelled = false;
}
public static class PictureView extends FrameLayout implements AsyncPictureLoaderCallback, CompoundButton.OnCheckedChangeListener {
private final AsyncPictureLoader loader;
private final CheckBox checkBox;
private final StateController stateController;
private final MediaCache pictureCache;
private ImageView vImage;
private PictureInfo pictureInfo;
public PictureView(MediaCache pictureCache, Context context, AsyncPictureLoader loader, StateController stateController) {
super(context);
this.pictureCache = pictureCache;
this.loader = loader;
this.stateController = stateController;
LayoutInflater.from(getContext()).inflate(getResourceId(getContext(), "layout", "view_media_item"), this);
vImage = (ImageView)findViewById(getResourceId(getContext(), "id", "vImage"));
checkBox = (CheckBox)findViewById(getResourceId(getContext(), "id", "checkBox"));
}
public void load(int position) {
if (pictureInfo != null) {
pictureInfo.cancelled = true;
}
pictureInfo = new PictureInfo();
pictureInfo.position = position;
pictureInfo.thumbnail = null;
pictureInfo.uri = null;
vImage.setImageResource(0);
vImage.setVisibility(INVISIBLE);
loader.loadThumbnail(pictureInfo, this);
updateSelection();
}
#Override
public void onLoad(PictureInfo picture) {
if (this.pictureInfo != picture) {
return;
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
vImage.setImageBitmap(pictureInfo.thumbnail);
vImage.setVisibility(VISIBLE);
}
});
}
}
}
I'm a beginner android developer and trying to create a Custom Pin Edittext using the following code and i want to set the color of the pin to transparent if filled,unfortunately there is no state_filled in the attr of android, how should i do that? Help me please here is my code.
public class PinEntryEditText extends AppCompatEditText {
public static final String XML_NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android";
private float mSpace = 24; //24 dp by default, space between the lines
private float mCharSize;
private float mNumChars = 6;
private float mLineSpacing = 8; //8dp by default, height of the text from our lines
private int mMaxLength = 6;
private OnClickListener mClickListener;
private float mLineStroke = 1; //1dp by default
private float mLineStrokeSelected = 2; //2dp by default
private Paint mLinesPaint;
int[][] mStates = new int[][]{
new int[]{android.R.attr.state_selected}, // selected
new int[]{android.R.attr.state_focused}, // focused
new int[]{-android.R.attr.state_focused}, // unfocused
};
//Green color = 0xFFB6C800
//Gray color = 0xFFCCCCCC
int[] mColors = new int[]{
0xFFB6C800,
0xFFCCCCCC,
0xFF880000,
};
ColorStateList mColorStates = new ColorStateList(mStates, mColors);
public PinEntryEditText(Context context) {
super(context);
}
public PinEntryEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public PinEntryEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
float multi = context.getResources().getDisplayMetrics().density;
mLineStroke = multi * mLineStroke;
mLineStrokeSelected = multi * mLineStrokeSelected;
mLinesPaint = new Paint(getPaint());
mLinesPaint.setStrokeWidth(mLineStroke);
setBackgroundResource(0);
mSpace = multi * mSpace; //convert to pixels for our density
mLineSpacing = multi * mLineSpacing; //convert to pixels for our density
mMaxLength = attrs.getAttributeIntValue(XML_NAMESPACE_ANDROID, "maxLength", 4);
mNumChars = mMaxLength;
//Disable copy paste
super.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
// When tapped, move cursor to end of text.
super.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
setSelection(getText().length());
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
});
}
#Override
public void setOnClickListener(OnClickListener l) {
mClickListener = l;
}
#Override
public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
throw new RuntimeException("setCustomSelectionActionModeCallback() not supported.");
}
#Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
int availableWidth = getWidth() - getPaddingRight() - getPaddingLeft();
if (mSpace < 0) {
mCharSize = (availableWidth / (mNumChars * 2 - 1));
} else {
mCharSize = (availableWidth - (mSpace * (mNumChars - 1))) / mNumChars;
}
int startX = getPaddingLeft();
int bottom = getHeight() - getPaddingBottom();
//Text Width
Editable text = getText();
int textLength = text.length();
float[] textWidths = new float[textLength];
getPaint().getTextWidths(getText(), 0, textLength, textWidths);
for (int i = 0; i < mNumChars; i++) {
updateColorForLines(i == textLength);
canvas.drawLine(startX, bottom, startX + mCharSize, bottom, mLinesPaint);
if (getText().length() > i) {
float middle = startX + mCharSize / 2;
canvas.drawText(text, i, i + 1, middle - textWidths[0] / 2, bottom - mLineSpacing, getPaint());
}
if (mSpace < 0) {
startX += mCharSize * 2;
} else {
startX += mCharSize + mSpace;
}
}
//mLinesPaint.setColor(getColorForState(0xff1a1f71));
}
private int getColorForState(int... states) {
return mColorStates.getColorForState(states, Color.GRAY);
}
/**
* #param next Is the current char the next character to be input?
*/
private void updateColorForLines(boolean next) {
if (isFocused()) {
mLinesPaint.setStrokeWidth(mLineStrokeSelected);
mLinesPaint.setColor(getColorForState(android.R.attr.state_focused));
if (next) {
mLinesPaint.setColor(getColorForState(android.R.attr.state_selected));
}
} else {
mLinesPaint.setStrokeWidth(mLineStroke);
mLinesPaint.setColor(getColorForState(-android.R.attr.state_focused));
}
}
}
Is there a way to do it?
there is no state_filled but you can create one. you can use TextWatcher interface it will be triggered whenever text will be updated. you can check there if current text size is equal to your mMaxLength set your pin color to transparent or else.
here is an example of TextWatcher implementation :
et1.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
I have a Gifview library which plays the animated gif. It's working fine in half screen but I need the gif to play in fullscreen mode. I Want to modify the onMeasure so that it can fit the fullscreen.
How can I change this method so that fullscreen is take in scale for each device?
public class GifView extends View {
private static final int DEFAULT_MOVIE_VIEW_DURATION = 1000;
private int mMovieResourceId;
private Movie movie;
private long mMovieStart;
private int mCurrentAnimationTime;
/**
* Position for drawing animation frames in the center of the view.
*/
private float mLeft;
private float mTop;
/**
* Scaling factor to fit the animation within view bounds.
*/
private float mScale;
/**
* Scaled movie frames width and height.
*/
private int mMeasuredMovieWidth;
private int mMeasuredMovieHeight;
private volatile boolean mPaused;
private boolean mVisible = true;
public GifView(Context context) {
this(context, null);
}
public GifView(Context context, AttributeSet attrs) {
this(context, attrs, R.styleable.CustomTheme_gifViewStyle);
}
public GifView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setViewAttributes(context, attrs, defStyle);
}
#SuppressLint("NewApi")
private void setViewAttributes(Context context, AttributeSet attrs, int defStyle) {
/**
* Starting from HONEYCOMB(Api Level:11) have to turn off HW acceleration to draw
* Movie on Canvas.
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
final TypedArray array = context.obtainStyledAttributes(attrs,
R.styleable.GifView, defStyle, R.style.Widget_GifView);
//-1 is default value
mMovieResourceId = array.getResourceId(R.styleable.GifView_gif, -1);
mPaused = array.getBoolean(R.styleable.GifView_paused, false);
array.recycle();
if (mMovieResourceId != -1) {
movie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
}
}
public void setGifResource(int movieResourceId) {
this.mMovieResourceId = movieResourceId;
movie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
requestLayout();
}
public int getGifResource() {
return this.mMovieResourceId;
}
public void play() {
if (this.mPaused) {
this.mPaused = false;
/**
* Calculate new movie start time, so that it resumes from the same
* frame.
*/
mMovieStart = android.os.SystemClock.uptimeMillis() - mCurrentAnimationTime;
invalidate();
}
}
//skip
public void next(){
if (this.mPaused) {
this.mPaused = false;
mMovieStart = mCurrentAnimationTime + movie.duration();
invalidate();
}
}
public void pause() {
if (!this.mPaused) {
this.mPaused = true;
invalidate();
}
}
public boolean isPaused() {
return this.mPaused;
}
public boolean isPlaying() {
return !this.mPaused;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (movie != null) {
int movieWidth = movie.width();
int movieHeight = movie.height();
/*
* Calculate horizontal scaling
*/
float scaleH = 1f;
int measureModeWidth = MeasureSpec.getMode(widthMeasureSpec);
if (measureModeWidth != MeasureSpec.UNSPECIFIED) {
int maximumWidth = MeasureSpec.getSize(widthMeasureSpec);
if (movieWidth > maximumWidth) {
scaleH = (float) movieWidth / (float) maximumWidth;
}
}
/*
* calculate vertical scaling
*/
float scaleW = 1f;
int measureModeHeight = MeasureSpec.getMode(heightMeasureSpec);
if (measureModeHeight != MeasureSpec.UNSPECIFIED) {
int maximumHeight = MeasureSpec.getSize(heightMeasureSpec);
if (movieHeight > maximumHeight) {
scaleW = (float) movieHeight / (float) maximumHeight;
}
}
/*
* calculate overall scale
*/
mScale = 1f / Math.max(scaleH, scaleW);
mMeasuredMovieWidth = (int) (movieWidth * mScale);
mMeasuredMovieHeight = (int) (movieHeight * mScale);
setMeasuredDimension(mMeasuredMovieWidth, mMeasuredMovieHeight);
} else {
/*
* No movie set, just set minimum available size.
*/
setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight());
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
/*
* Calculate mLeft / mTop for drawing in center
*/
mLeft = (getWidth() - mMeasuredMovieWidth) / 2f;
mTop = (getHeight() - mMeasuredMovieHeight) / 2f;
mVisible = getVisibility() == View.VISIBLE;
}
#Override
protected void onDraw(Canvas canvas) {
if (movie != null) {
if (!mPaused) {
updateAnimationTime();
drawMovieFrame(canvas);
invalidateView();
} else {
drawMovieFrame(canvas);
}
}
}
/**
* Invalidates view only if it is mVisible.
* <br>
* {#link #postInvalidateOnAnimation()} is used for Jelly Bean and higher.
*/
#SuppressLint("NewApi")
private void invalidateView() {
if (mVisible) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
postInvalidateOnAnimation();
} else {
invalidate();
}
}
}
/**
* Calculate current animation time
*/
private void updateAnimationTime() {
long now = android.os.SystemClock.uptimeMillis();
if (mMovieStart == 0) {
mMovieStart = now;
}
int dur = movie.duration();
if (dur == 0) {
dur = DEFAULT_MOVIE_VIEW_DURATION;
}
mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
// Log.d(TAG, "updateAnimationTime: " + mCurrentAnimationTime);
}
/**
* Draw current GIF frame
*/
private void drawMovieFrame(Canvas canvas) {
movie.setTime(mCurrentAnimationTime);
// canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScale, mScale);
movie.draw(canvas, mLeft / mScale, mTop / mScale);
canvas.restore();
}
#SuppressLint("NewApi")
#Override
public void onScreenStateChanged(int screenState) {
super.onScreenStateChanged(screenState);
mVisible = screenState == SCREEN_STATE_ON;
invalidateView();
}
#SuppressLint("NewApi")
#Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
mVisible = visibility == View.VISIBLE;
invalidateView();
}
#Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mVisible = visibility == View.VISIBLE;
invalidateView();
}
}
xml layout
<com.world.example.GifView
android:id="#+id/gif1"
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:gif="#mipmap/tiktok" />
I want the gif image to play in fullscreen mode.
Try android:scaleType="fitXY" in xml layout
<com.world.example.GifView
android:id="#+id/mygif"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"/>
Hope it helps !
So I am trying to make a Listview you can drag and drop the rows. I got it to work ok, but when I add an item to the Listview it breaks (here is what the bug looks like: http://youtu.be/VYRYh0Vwq6o). What is causing this problem and how do I fix it? Thanks in advance.
Heres my code:
ItemsArrayAdapter.xml
package benawad.com.todolist.adapters;
import android.content.Context;
import android.graphics.Paint;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import benawad.com.todolist.NoteActivity;
import benawad.com.todolist.R;
public class ItemsArrayAdapter extends ArrayAdapter<String> {
public static final String TAG = ItemsArrayAdapter.class.getSimpleName();
Context mContext;
ArrayList<String> mArrayList;
boolean wantsSlash;
NoteActivity mNoteActivity;
EditText mNewItemText;
final int INVALID_ID = -1;
HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
public ItemsArrayAdapter
(NoteActivity context, ArrayList<String> arrayList, boolean slashes){
super(context, R.layout.item_row,arrayList);
mContext = context;
mArrayList = arrayList;
mNoteActivity = context;
wantsSlash = slashes;
update();
}
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_row, parent, false);
holder = new ViewHolder();
holder.itemName = (TextView)convertView.findViewById(R.id.itemText);
for (int i = 0; i < mArrayList.size(); ++i) {
mIdMap.put(mArrayList.get(i), i);
}
holder.delete = (ImageView)convertView.findViewById(R.id.delete_item);
holder.edit = (ImageView)convertView.findViewById(R.id.edit_item);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.itemName.setText(mArrayList.get(position));
if(wantsSlash){
holder.itemName.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG);
}
holder.delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mNoteActivity.deleteItem(position);
}
});
holder.edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mNoteActivity.editItem(position);
}
});
return convertView;
}
private static class ViewHolder {
TextView itemName;
ImageView edit;
ImageView delete;
}
#Override
public long getItemId(int position) {
Long idToReturn = (long) INVALID_ID;
if (position >= 0 && position <= mIdMap.size()-1) {
try {
String item = getItem(position);
idToReturn = (long) mIdMap.get(item);
}
catch(Exception e){}
}
return idToReturn;
}
// #Override
// public long getItemId(int position) {
// if (position < 0 || position >= mIdMap.size()) {
// return INVALID_ID;
// }
// String item = getItem(position);
// return mIdMap.get(item);
// }
public void update(){
for (int i = 0; i < mArrayList.size(); ++i) {
mIdMap.put(mArrayList.get(i), i);
}
}
#Override
public boolean hasStableIds() {
return true;
}
}
DynamicListView.java
package benawad.com.todolist;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import benawad.com.todolist.adapters.ItemsArrayAdapter;
public class DynamicListView extends ListView {
final static String TAG = DynamicListView.class.getSimpleName();
private final int SMOOTH_SCROLL_AMOUNT_AT_EDGE = 15;
private final int MOVE_DURATION = 150;
private final int LINE_THICKNESS = 15;
public ArrayList<String> mCheeseList;
private int mLastEventY = -1;
private int mDownY = -1;
private int mDownX = -1;
private int mTotalOffset = 0;
private boolean mCellIsMobile = false;
private boolean mIsMobileScrolling = false;
private int mSmoothScrollAmountAtEdge = 0;
private final int INVALID_ID = -1;
private long mAboveItemId = INVALID_ID;
private long mMobileItemId = INVALID_ID;
private long mBelowItemId = INVALID_ID;
private BitmapDrawable mHoverCell;
private Rect mHoverCellCurrentBounds;
private Rect mHoverCellOriginalBounds;
private final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private boolean mIsWaitingForScrollFinish = false;
private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
public DynamicListView(Context context) {
super(context);
init(context);
}
public DynamicListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public DynamicListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public void init(Context context) {
setOnItemLongClickListener(mOnItemLongClickListener);
setOnScrollListener(mScrollListener);
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
mSmoothScrollAmountAtEdge = (int)(SMOOTH_SCROLL_AMOUNT_AT_EDGE / metrics.density);
}
/**
* Listens for long clicks on any mItems in the listview. When a cell has
* been selected, the hover cell is created and set up.
*/
private OnItemLongClickListener mOnItemLongClickListener =
new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int pos, long id) {
mTotalOffset = 0;
int position = pointToPosition(mDownX, mDownY);
int itemNum = position - getFirstVisiblePosition();
View selectedView = getChildAt(itemNum);
mMobileItemId = getAdapter().getItemId(position);
mHoverCell = getAndAddHoverView(selectedView);
selectedView.setVisibility(INVISIBLE);
mCellIsMobile = true;
updateNeighborViewsForID(mMobileItemId);
return true;
}
};
/**
* Creates the hover cell with the appropriate bitmap and of appropriate
* size. The hover cell's BitmapDrawable is drawn on top of the bitmap every
* single time an invalidate call is made.
*/
private BitmapDrawable getAndAddHoverView(View v) {
int w = v.getWidth();
int h = v.getHeight();
int top = v.getTop();
int left = v.getLeft();
Bitmap b = getBitmapWithBorder(v);
BitmapDrawable drawable = new BitmapDrawable(getResources(), b);
mHoverCellOriginalBounds = new Rect(left, top, left + w, top + h);
mHoverCellCurrentBounds = new Rect(mHoverCellOriginalBounds);
drawable.setBounds(mHoverCellCurrentBounds);
return drawable;
}
/** Draws a black border over the screenshot of the view passed in. */
private Bitmap getBitmapWithBorder(View v) {
Bitmap bitmap = getBitmapFromView(v);
Canvas can = new Canvas(bitmap);
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(LINE_THICKNESS);
paint.setColor(Color.BLACK);
can.drawBitmap(bitmap, 0, 0, null);
can.drawRect(rect, paint);
return bitmap;
}
/** Returns a bitmap showing a screenshot of the view passed in. */
private Bitmap getBitmapFromView(View v) {
Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas (bitmap);
v.draw(canvas);
return bitmap;
}
/**
* Stores a reference to the views above and below the item currently
* corresponding to the hover cell. It is important to note that if this
* item is either at the top or bottom of the list, mAboveItemId or mBelowItemId
* may be invalid.
*/
private void updateNeighborViewsForID(long itemID) {
int position = getPositionForID(itemID);
ItemsArrayAdapter adapter = ((ItemsArrayAdapter)getAdapter());
mAboveItemId = adapter.getItemId(position - 1);
mBelowItemId = adapter.getItemId(position + 1);
}
/** Retrieves the view in the list corresponding to itemID */
public View getViewForID (long itemID) {
int firstVisiblePosition = getFirstVisiblePosition();
ItemsArrayAdapter adapter = ((ItemsArrayAdapter)getAdapter());
for(int i = 0; i < getChildCount(); i++) {
View v = getChildAt(i);
int position = firstVisiblePosition + i;
long id = adapter.getItemId(position);
if (id == itemID) {
return v;
}
}
return null;
}
/** Retrieves the position in the list corresponding to itemID */
public int getPositionForID (long itemID) {
View v = getViewForID(itemID);
if (v == null) {
return -1;
} else {
return getPositionForView(v);
}
}
/**
* dispatchDraw gets invoked when all the child views are about to be drawn.
* By overriding this method, the hover cell (BitmapDrawable) can be drawn
* over the listview's mItems whenever the listview is redrawn.
*/
#Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mHoverCell != null) {
mHoverCell.draw(canvas);
}
}
#Override
public boolean onTouchEvent (MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mDownX = (int)event.getX();
mDownY = (int)event.getY();
mActivePointerId = event.getPointerId(0);
break;
case MotionEvent.ACTION_MOVE:
if (mActivePointerId == INVALID_POINTER_ID) {
break;
}
int pointerIndex = event.findPointerIndex(mActivePointerId);
mLastEventY = (int) event.getY(pointerIndex);
int deltaY = mLastEventY - mDownY;
if (mCellIsMobile) {
mHoverCellCurrentBounds.offsetTo(mHoverCellOriginalBounds.left,
mHoverCellOriginalBounds.top + deltaY + mTotalOffset);
mHoverCell.setBounds(mHoverCellCurrentBounds);
invalidate();
handleCellSwitch();
mIsMobileScrolling = false;
handleMobileCellScroll();
return false;
}
break;
case MotionEvent.ACTION_UP:
touchEventsEnded();
break;
case MotionEvent.ACTION_CANCEL:
touchEventsCancelled();
break;
case MotionEvent.ACTION_POINTER_UP:
/* If a multitouch event took place and the original touch dictating
* the movement of the hover cell has ended, then the dragging event
* ends and the hover cell is animated to its corresponding position
* in the listview. */
pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
touchEventsEnded();
}
break;
default:
break;
}
return super.onTouchEvent(event);
}
/**
* This method determines whether the hover cell has been shifted far enough
* to invoke a cell swap. If so, then the respective cell swap candidate is
* determined and the data set is changed. Upon posting a notification of the
* data set change, a layout is invoked to place the cells in the right place.
* Using a ViewTreeObserver and a corresponding OnPreDrawListener, we can
* offset the cell being swapped to where it previously was and then animate it to
* its new position.
*/
private void handleCellSwitch() {
final int deltaY = mLastEventY - mDownY;
int deltaYTotal = mHoverCellOriginalBounds.top + mTotalOffset + deltaY;
View belowView = getViewForID(mBelowItemId);
View mobileView = getViewForID(mMobileItemId);
View aboveView = getViewForID(mAboveItemId);
boolean isBelow = (belowView != null) && (deltaYTotal > belowView.getTop());
boolean isAbove = (aboveView != null) && (deltaYTotal < aboveView.getTop());
if (isBelow || isAbove) {
final long switchItemID = isBelow ? mBelowItemId : mAboveItemId;
View switchView = isBelow ? belowView : aboveView;
final int originalItem = getPositionForView(mobileView);
if (switchView == null) {
updateNeighborViewsForID(mMobileItemId);
return;
}
swapElements(mCheeseList, originalItem, getPositionForView(switchView));
((BaseAdapter) getAdapter()).notifyDataSetChanged();
mDownY = mLastEventY;
final int switchViewStartTop = switchView.getTop();
if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.KITKAT){
mobileView.setVisibility(View.VISIBLE);
switchView.setVisibility(View.INVISIBLE);
} else{
mobileView.setVisibility(View.INVISIBLE);
switchView.setVisibility(View.VISIBLE);
}
updateNeighborViewsForID(mMobileItemId);
final ViewTreeObserver observer = getViewTreeObserver();
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
observer.removeOnPreDrawListener(this);
View switchView = getViewForID(switchItemID);
mTotalOffset += deltaY;
int switchViewNewTop = switchView.getTop();
int delta = switchViewStartTop - switchViewNewTop;
switchView.setTranslationY(delta);
ObjectAnimator animator = ObjectAnimator.ofFloat(switchView,
View.TRANSLATION_Y, 0);
animator.setDuration(MOVE_DURATION);
animator.start();
return true;
}
});
}
}
private void swapElements(ArrayList arrayList, int indexOne, int indexTwo) {
Object temp = arrayList.get(indexOne);
arrayList.set(indexOne, arrayList.get(indexTwo));
arrayList.set(indexTwo, temp);
}
/**
* Resets all the appropriate fields to a default state while also animating
* the hover cell back to its correct location.
*/
private void touchEventsEnded () {
final View mobileView = getViewForID(mMobileItemId);
if (mCellIsMobile|| mIsWaitingForScrollFinish) {
mCellIsMobile = false;
mIsWaitingForScrollFinish = false;
mIsMobileScrolling = false;
mActivePointerId = INVALID_POINTER_ID;
// If the autoscroller has not completed scrolling, we need to wait for it to
// finish in order to determine the final location of where the hover cell
// should be animated to.
if (mScrollState != OnScrollListener.SCROLL_STATE_IDLE) {
mIsWaitingForScrollFinish = true;
return;
}
mHoverCellCurrentBounds.offsetTo(mHoverCellOriginalBounds.left, mobileView.getTop());
ObjectAnimator hoverViewAnimator = ObjectAnimator.ofObject(mHoverCell, "bounds",
sBoundEvaluator, mHoverCellCurrentBounds);
hoverViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
invalidate();
}
});
hoverViewAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
setEnabled(false);
}
#Override
public void onAnimationEnd(Animator animation) {
mAboveItemId = INVALID_ID;
mMobileItemId = INVALID_ID;
mBelowItemId = INVALID_ID;
mobileView.setVisibility(VISIBLE);
mHoverCell = null;
setEnabled(true);
invalidate();
}
});
hoverViewAnimator.start();
} else {
touchEventsCancelled();
}
}
/**
* Resets all the appropriate fields to a default state.
*/
private void touchEventsCancelled () {
View mobileView = getViewForID(mMobileItemId);
if (mCellIsMobile) {
mAboveItemId = INVALID_ID;
mMobileItemId = INVALID_ID;
mBelowItemId = INVALID_ID;
mobileView.setVisibility(VISIBLE);
mHoverCell = null;
invalidate();
}
mCellIsMobile = false;
mIsMobileScrolling = false;
mActivePointerId = INVALID_POINTER_ID;
}
/**
* This TypeEvaluator is used to animate the BitmapDrawable back to its
* final location when the user lifts his finger by modifying the
* BitmapDrawable's bounds.
*/
private final static TypeEvaluator<Rect> sBoundEvaluator = new TypeEvaluator<Rect>() {
public Rect evaluate(float fraction, Rect startValue, Rect endValue) {
return new Rect(interpolate(startValue.left, endValue.left, fraction),
interpolate(startValue.top, endValue.top, fraction),
interpolate(startValue.right, endValue.right, fraction),
interpolate(startValue.bottom, endValue.bottom, fraction));
}
public int interpolate(int start, int end, float fraction) {
return (int)(start + fraction * (end - start));
}
};
/**
* Determines whether this listview is in a scrolling state invoked
* by the fact that the hover cell is out of the bounds of the listview;
*/
private void handleMobileCellScroll() {
mIsMobileScrolling = handleMobileCellScroll(mHoverCellCurrentBounds);
}
/**
* This method is in charge of determining if the hover cell is above
* or below the bounds of the listview. If so, the listview does an appropriate
* upward or downward smooth scroll so as to reveal new mItems.
*/
public boolean handleMobileCellScroll(Rect r) {
int offset = computeVerticalScrollOffset();
int height = getHeight();
int extent = computeVerticalScrollExtent();
int range = computeVerticalScrollRange();
int hoverViewTop = r.top;
int hoverHeight = r.height();
if (hoverViewTop <= 0 && offset > 0) {
smoothScrollBy(-mSmoothScrollAmountAtEdge, 0);
return true;
}
if (hoverViewTop + hoverHeight >= height && (offset + extent) < range) {
smoothScrollBy(mSmoothScrollAmountAtEdge, 0);
return true;
}
return false;
}
public void setCheeseList(ArrayList<String> cheeseList) {
mCheeseList = cheeseList;
}
/**
* This scroll listener is added to the listview in order to handle cell swapping
* when the cell is either at the top or bottom edge of the listview. If the hover
* cell is at either edge of the listview, the listview will begin scrolling. As
* scrolling takes place, the listview continuously checks if new cells became visible
* and determines whether they are potential candidates for a cell swap.
*/
private OnScrollListener mScrollListener = new OnScrollListener () {
private int mPreviousFirstVisibleItem = -1;
private int mPreviousVisibleItemCount = -1;
private int mCurrentFirstVisibleItem;
private int mCurrentVisibleItemCount;
private int mCurrentScrollState;
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
mCurrentFirstVisibleItem = firstVisibleItem;
mCurrentVisibleItemCount = visibleItemCount;
mPreviousFirstVisibleItem = (mPreviousFirstVisibleItem == -1) ? mCurrentFirstVisibleItem
: mPreviousFirstVisibleItem;
mPreviousVisibleItemCount = (mPreviousVisibleItemCount == -1) ? mCurrentVisibleItemCount
: mPreviousVisibleItemCount;
checkAndHandleFirstVisibleCellChange();
checkAndHandleLastVisibleCellChange();
mPreviousFirstVisibleItem = mCurrentFirstVisibleItem;
mPreviousVisibleItemCount = mCurrentVisibleItemCount;
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
mCurrentScrollState = scrollState;
mScrollState = scrollState;
isScrollCompleted();
}
/**
* This method is in charge of invoking 1 of 2 actions. Firstly, if the listview
* is in a state of scrolling invoked by the hover cell being outside the bounds
* of the listview, then this scrolling event is continued. Secondly, if the hover
* cell has already been released, this invokes the animation for the hover cell
* to return to its correct position after the listview has entered an idle scroll
* state.
*/
private void isScrollCompleted() {
if (mCurrentVisibleItemCount > 0 && mCurrentScrollState == SCROLL_STATE_IDLE) {
if (mCellIsMobile && mIsMobileScrolling) {
handleMobileCellScroll();
} else if (mIsWaitingForScrollFinish) {
touchEventsEnded();
}
}
}
/**
* Determines if the listview scrolled up enough to reveal a new cell at the
* top of the list. If so, then the appropriate parameters are updated.
*/
public void checkAndHandleFirstVisibleCellChange() {
if (mCurrentFirstVisibleItem != mPreviousFirstVisibleItem) {
if (mCellIsMobile && mMobileItemId != INVALID_ID) {
updateNeighborViewsForID(mMobileItemId);
handleCellSwitch();
}
}
}
/**
* Determines if the listview scrolled down enough to reveal a new cell at the
* bottom of the list. If so, then the appropriate parameters are updated.
*/
public void checkAndHandleLastVisibleCellChange() {
int currentLastVisibleItem = mCurrentFirstVisibleItem + mCurrentVisibleItemCount;
int previousLastVisibleItem = mPreviousFirstVisibleItem + mPreviousVisibleItemCount;
if (currentLastVisibleItem != previousLastVisibleItem) {
if (mCellIsMobile && mMobileItemId != INVALID_ID) {
updateNeighborViewsForID(mMobileItemId);
handleCellSwitch();
}
}
}
};
}
Ran out of characters here is NoteActivity.java on pastebin.com: http://pastebin.com/MgaFXHb6
If you need to see any other code let me know.
I give u some link for hint:
https://github.com/twotoasters/jazzylistview
https://play.google.com/store/apps/details?id=com.twotoasters.jazzylistview.sample
I already implemented JazzylistView but I also want to implement JazzylistView with PullToRefresh ListView. Is this possible? Anyone know this answer , please help me?
I find this solution. Just copy paste below code in PullToRefreshListView .java file in the library.
package com.smartupdater.widget;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.notecrate.R;
import com.smartupdater.utils.Constants;
public class PullToRefreshListView extends ListView {
private final JazzyHelper mHelper;
private static final float PULL_RESISTANCE = 1.7f;
private static final int BOUNCE_ANIMATION_DURATION = 700;
private static final int BOUNCE_ANIMATION_DELAY = 100;
private static final float BOUNCE_OVERSHOOT_TENSION = 1.4f;
private static final int ROTATE_ARROW_ANIMATION_DURATION = 250;
private static enum State {
PULL_TO_REFRESH, RELEASE_TO_REFRESH, REFRESHING
}
/**
* Interface to implement when you want to get notified of 'pull to refresh'
* events. Call setOnRefreshListener(..) to activate an OnRefreshListener.
*/
public interface OnRefreshListener {
/**
* Method to be called when a refresh is requested
*/
public void onRefresh();
}
private static int measuredHeaderHeight;
private boolean scrollbarEnabled;
private boolean bounceBackHeader;
private boolean lockScrollWhileRefreshing;
private boolean showLastUpdatedText;
private String pullToRefreshText;
private String releaseToRefreshText;
private String refreshingText;
private String lastUpdatedText;
private SimpleDateFormat lastUpdatedDateFormat = new SimpleDateFormat("dd/MM HH:mm");
private float previousY;
private int headerPadding;
private boolean hasResetHeader;
private long lastUpdated = -1;
private State state;
private LinearLayout headerContainer;
private RelativeLayout header;
private RotateAnimation flipAnimation;
private RotateAnimation reverseFlipAnimation;
private ImageView image;
private ProgressBar spinner;
private TextView text;
private TextView lastUpdatedTextView;
private OnItemClickListener onItemClickListener;
private OnItemLongClickListener onItemLongClickListener;
private OnRefreshListener onRefreshListener;
public PullToRefreshListView(Context context) {
super(context);
mHelper = init(context, null);
init();
}
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
mHelper = init(context, attrs);
init();
}
public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mHelper = init(context, attrs);
init();
}
private JazzyHelper init(Context context, AttributeSet attrs) {
JazzyHelper helper = new JazzyHelper(context, attrs);
super.setOnScrollListener(helper);
return helper;
}
#Override
public final void setOnScrollListener(OnScrollListener l) {
mHelper.setOnScrollListener(l);
}
public void setTransitionEffect(int transitionEffect) {
mHelper.setTransitionEffect(transitionEffect);
}
public void setShouldOnlyAnimateNewItems(boolean onlyAnimateNew) {
mHelper.setShouldOnlyAnimateNewItems(onlyAnimateNew);
}
public void setShouldOnlyAnimateFling(boolean onlyFling) {
mHelper.setShouldOnlyAnimateFling(onlyFling);
}
public void setSimulateGridWithList(boolean simulateGridWithList) {
mHelper.setSimulateGridWithList(simulateGridWithList);
setClipChildren(!simulateGridWithList);
}
public void setMaxAnimationVelocity(int itemsPerSecond) {
mHelper.setMaxAnimationVelocity(itemsPerSecond);
}
#Override
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
#Override
public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
this.onItemLongClickListener = onItemLongClickListener;
}
/**
* Activate an OnRefreshListener to get notified on 'pull to refresh'
* events.
*
* #param onRefreshListener
* The OnRefreshListener to get notified
*/
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
this.onRefreshListener = onRefreshListener;
}
/**
* #return If the list is in 'Refreshing' state
*/
public boolean isRefreshing() {
return state == State.REFRESHING;
}
/**
* Default is false. When lockScrollWhileRefreshing is set to true, the list
* cannot scroll when in 'refreshing' mode. It's 'locked' on refreshing.
*
* #param lockScrollWhileRefreshing
*/
public void setLockScrollWhileRefreshing(boolean lockScrollWhileRefreshing) {
this.lockScrollWhileRefreshing = lockScrollWhileRefreshing;
}
/**
* Default is false. Show the last-updated date/time in the 'Pull ro
* Refresh' header. See 'setLastUpdatedDateFormat' to set the date/time
* formatting.
*
* #param showLastUpdatedText
*/
public void setShowLastUpdatedText(boolean showLastUpdatedText) {
this.showLastUpdatedText = showLastUpdatedText;
if (!showLastUpdatedText)
lastUpdatedTextView.setVisibility(View.GONE);
}
/**
* Default: "dd/MM HH:mm". Set the format in which the last-updated
* date/time is shown. Meaningless if 'showLastUpdatedText == false
* (default)'. See 'setShowLastUpdatedText'.
*
* #param lastUpdatedDateFormat
*/
public void setLastUpdatedDateFormat(SimpleDateFormat lastUpdatedDateFormat) {
this.lastUpdatedDateFormat = lastUpdatedDateFormat;
}
/**
* Explicitly set the state to refreshing. This is useful when you want to
* show the spinner and 'Refreshing' text when the refresh was not triggered
* by 'pull to refresh', for example on start.
*/
public void setRefreshing() {
state = State.REFRESHING;
scrollTo(0, 0);
setUiRefreshing();
setHeaderPadding(0);
}
/**
* Set the state back to 'pull to refresh'. Call this method when refreshing
* the data is finished.
*/
public void onRefreshComplete() {
state = State.PULL_TO_REFRESH;
resetHeader();
lastUpdated = System.currentTimeMillis();
}
/**
* Change the label text on state 'Pull to Refresh'
*
* #param pullToRefreshText
* Text
*/
public void setTextPullToRefresh(String pullToRefreshText) {
this.pullToRefreshText = pullToRefreshText;
if (state == State.PULL_TO_REFRESH) {
text.setText(pullToRefreshText);
}
}
/**
* Change the label text on state 'Release to Refresh'
*
* #param releaseToRefreshText
* Text
*/
public void setTextReleaseToRefresh(String releaseToRefreshText) {
this.releaseToRefreshText = releaseToRefreshText;
if (state == State.RELEASE_TO_REFRESH) {
text.setText(releaseToRefreshText);
}
}
/**
* Change the label text on state 'Refreshing'
*
* #param refreshingText
* Text
*/
public void setTextRefreshing(String refreshingText) {
this.refreshingText = refreshingText;
if (state == State.REFRESHING) {
text.setText(refreshingText);
}
}
private void init() {
setVerticalFadingEdgeEnabled(false);
headerContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.layout_pulldown_header, null);
header = (RelativeLayout) headerContainer.findViewById(R.id.ptr_id_header);
text = (TextView) header.findViewById(R.id.ptr_id_text);
lastUpdatedTextView = (TextView) header.findViewById(R.id.ptr_id_last_updated);
image = (ImageView) header.findViewById(R.id.ptr_id_image);
spinner = (ProgressBar) header.findViewById(R.id.ptr_id_spinner);
pullToRefreshText = getContext().getString(R.string.ptr_pull_to_refresh);
releaseToRefreshText = getContext().getString(R.string.ptr_release_to_refresh);
refreshingText = getContext().getString(R.string.ptr_refreshing);
lastUpdatedText = getContext().getString(R.string.ptr_last_updated);
flipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
flipAnimation.setInterpolator(new LinearInterpolator());
flipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION);
flipAnimation.setFillAfter(true);
reverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
reverseFlipAnimation.setInterpolator(new LinearInterpolator());
reverseFlipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION);
reverseFlipAnimation.setFillAfter(true);
addHeaderView(headerContainer);
setState(State.PULL_TO_REFRESH);
scrollbarEnabled = isVerticalScrollBarEnabled();
ViewTreeObserver vto = header.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new PTROnGlobalLayoutListener());
super.setOnItemClickListener(new PTROnItemClickListener());
super.setOnItemLongClickListener(new PTROnItemLongClickListener());
}
private void setHeaderPadding(int padding) {
headerPadding = padding;
// Log.d(Constants.TAG, "Header Container=" + headerContainer +
// " Header=" + header + " Header Padding=" + headerPadding);
if (header != null) {
MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) header.getLayoutParams();
mlp.setMargins(0, Math.round(padding), 0, 0);
header.setLayoutParams(mlp);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (lockScrollWhileRefreshing && (state == State.REFRESHING || getAnimation() != null && !getAnimation().hasEnded())) {
return true;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (getFirstVisiblePosition() == 0)
previousY = event.getY();
else
previousY = -1;
break;
case MotionEvent.ACTION_UP:
if (previousY != -1 && (state == State.RELEASE_TO_REFRESH || getFirstVisiblePosition() == 0)) {
switch (state) {
case RELEASE_TO_REFRESH:
setState(State.REFRESHING);
bounceBackHeader();
break;
case PULL_TO_REFRESH:
resetHeader();
break;
}
}
break;
case MotionEvent.ACTION_MOVE:
if (previousY != -1) {
float y = event.getY();
float diff = y - previousY;
if (diff > 0)
diff /= PULL_RESISTANCE;
previousY = y;
int newHeaderPadding = Math.max(Math.round(headerPadding + diff), -header.getHeight());
if (newHeaderPadding != headerPadding && state != State.REFRESHING) {
setHeaderPadding(newHeaderPadding);
if (state == State.PULL_TO_REFRESH && headerPadding > 0) {
setState(State.RELEASE_TO_REFRESH);
image.clearAnimation();
image.startAnimation(flipAnimation);
} else if (state == State.RELEASE_TO_REFRESH && headerPadding < 0) {
setState(State.PULL_TO_REFRESH);
image.clearAnimation();
image.startAnimation(reverseFlipAnimation);
}
return true;
}
}
break;
}
return super.onTouchEvent(event);
}
private void bounceBackHeader() {
int yTranslate = state == State.REFRESHING ? header.getHeight() - headerContainer.getHeight() : -headerContainer.getHeight()
- headerContainer.getTop();
TranslateAnimation bounceAnimation = new TranslateAnimation(TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, 0,
TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, yTranslate);
bounceAnimation.setDuration(BOUNCE_ANIMATION_DURATION);
bounceAnimation.setFillEnabled(true);
bounceAnimation.setFillAfter(false);
bounceAnimation.setFillBefore(true);
bounceAnimation.setInterpolator(new OvershootInterpolator(BOUNCE_OVERSHOOT_TENSION));
bounceAnimation.setAnimationListener(new HeaderAnimationListener(yTranslate));
startAnimation(bounceAnimation);
}
private void resetHeader() {
if (getFirstVisiblePosition() > 0) {
setHeaderPadding(-header.getHeight());
setState(State.PULL_TO_REFRESH);
return;
}
if (getAnimation() != null && !getAnimation().hasEnded()) {
bounceBackHeader = true;
} else {
bounceBackHeader();
}
}
private void setUiRefreshing() {
spinner.setVisibility(View.VISIBLE);
image.clearAnimation();
image.setVisibility(View.INVISIBLE);
text.setText(refreshingText);
}
private void setState(State state) {
this.state = state;
switch (state) {
case PULL_TO_REFRESH:
spinner.setVisibility(View.INVISIBLE);
image.setVisibility(View.VISIBLE);
text.setText(pullToRefreshText);
if (showLastUpdatedText && lastUpdated != -1) {
lastUpdatedTextView.setVisibility(View.VISIBLE);
lastUpdatedTextView.setText(String.format(lastUpdatedText, lastUpdatedDateFormat.format(new Date(lastUpdated))));
}
break;
case RELEASE_TO_REFRESH:
spinner.setVisibility(View.INVISIBLE);
image.setVisibility(View.VISIBLE);
text.setText(releaseToRefreshText);
break;
case REFRESHING:
setUiRefreshing();
lastUpdated = System.currentTimeMillis();
if (onRefreshListener == null) {
setState(State.PULL_TO_REFRESH);
} else {
onRefreshListener.onRefresh();
}
break;
}
}
#Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (!hasResetHeader) {
if (measuredHeaderHeight > 0 && state != State.REFRESHING) {
setHeaderPadding(-measuredHeaderHeight);
}
hasResetHeader = true;
}
}
private class HeaderAnimationListener implements AnimationListener {
private int height, translation;
private State stateAtAnimationStart;
public HeaderAnimationListener(int translation) {
this.translation = translation;
}
#Override
public void onAnimationStart(Animation animation) {
stateAtAnimationStart = state;
android.view.ViewGroup.LayoutParams lp = getLayoutParams();
height = lp.height;
lp.height = getHeight() - translation;
setLayoutParams(lp);
if (scrollbarEnabled) {
setVerticalScrollBarEnabled(false);
}
}
#Override
public void onAnimationEnd(Animation animation) {
setHeaderPadding(stateAtAnimationStart == State.REFRESHING ? 0 : -measuredHeaderHeight - headerContainer.getTop());
setSelection(0);
android.view.ViewGroup.LayoutParams lp = getLayoutParams();
lp.height = height;
setLayoutParams(lp);
if (scrollbarEnabled) {
setVerticalScrollBarEnabled(true);
}
if (bounceBackHeader) {
bounceBackHeader = false;
postDelayed(new Runnable() {
#Override
public void run() {
resetHeader();
}
}, BOUNCE_ANIMATION_DELAY);
} else if (stateAtAnimationStart != State.REFRESHING) {
setState(State.PULL_TO_REFRESH);
}
}
#Override
public void onAnimationRepeat(Animation animation) {
}
}
private class PTROnGlobalLayoutListener implements OnGlobalLayoutListener {
#Override
public void onGlobalLayout() {
int initialHeaderHeight = header.getHeight();
if (initialHeaderHeight > 0) {
measuredHeaderHeight = initialHeaderHeight;
if (measuredHeaderHeight > 0 && state != State.REFRESHING) {
setHeaderPadding(-measuredHeaderHeight);
requestLayout();
}
}
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
private class PTROnItemClickListener implements OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
hasResetHeader = false;
if (onItemClickListener != null && state == State.PULL_TO_REFRESH) {
// Passing up onItemClick. Correct position with the number of
// header views
onItemClickListener.onItemClick(adapterView, view, position - getHeaderViewsCount(), id);
}
}
}
private class PTROnItemLongClickListener implements OnItemLongClickListener {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
hasResetHeader = false;
if (onItemLongClickListener != null && state == State.PULL_TO_REFRESH) {
// Passing up onItemLongClick. Correct position with the number
// of header views
return onItemLongClickListener.onItemLongClick(adapterView, view, position - getHeaderViewsCount(), id);
}
return false;
}
}
}
In fact,you can combine the two frame by modify the source code.
first,modify PullToRefreshAdapterViewBase.java
remove the final,because you have override it in PullToRefreshListView.the purpose is hijack the OnScrollListener,pass it to JazzyHelper.
public void setOnScrollListener(OnScrollListener listener) {
mOnScrollListener = listener;
}
the code in PullToRefreshListView.java.
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.handmark.pulltorefresh.library;
import com.example.jazzydemo.R;
import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor;
import com.handmark.pulltorefresh.library.internal.LoadingLayout;
import com.xp.lvbh.others.jazzylistview.JazzyEffect;
import com.xp.lvbh.others.jazzylistview.JazzyHelper;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.AbsListView.OnScrollListener;
public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView> {
private final JazzyHelper mHelper;
private LoadingLayout mHeaderLoadingView;
private LoadingLayout mFooterLoadingView;
private FrameLayout mLvFooterLoadingFrame;
private boolean mListViewExtrasEnabled;
public PullToRefreshListView(Context context) {
super(context);
mHelper = init(context, null);
}
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
mHelper = init(context, null);
}
public PullToRefreshListView(Context context, Mode mode) {
super(context, mode);
mHelper = init(context, null);
}
public PullToRefreshListView(Context context, Mode mode, AnimationStyle style) {
super(context, mode, style);
mHelper = init(context, null);
}
#Override
public final Orientation getPullToRefreshScrollDirection() {
return Orientation.VERTICAL;
}
#Override
protected void onRefreshing(final boolean doScroll) {
/**
* If we're not showing the Refreshing view, or the list is empty, the
* the header/footer views won't show so we use the normal method.
*/
ListAdapter adapter = mRefreshableView.getAdapter();
if (!mListViewExtrasEnabled || !getShowViewWhileRefreshing() || null == adapter || adapter.isEmpty()) {
super.onRefreshing(doScroll);
return;
}
super.onRefreshing(false);
final LoadingLayout origLoadingView, listViewLoadingView, oppositeListViewLoadingView;
final int selection, scrollToY;
switch (getCurrentMode()) {
case MANUAL_REFRESH_ONLY:
case PULL_FROM_END:
origLoadingView = getFooterLayout();
listViewLoadingView = mFooterLoadingView;
oppositeListViewLoadingView = mHeaderLoadingView;
selection = mRefreshableView.getCount() - 1;
scrollToY = getScrollY() - getFooterSize();
break;
case PULL_FROM_START:
default:
origLoadingView = getHeaderLayout();
listViewLoadingView = mHeaderLoadingView;
oppositeListViewLoadingView = mFooterLoadingView;
selection = 0;
scrollToY = getScrollY() + getHeaderSize();
break;
}
// Hide our original Loading View
origLoadingView.reset();
origLoadingView.hideAllViews();
// Make sure the opposite end is hidden too
oppositeListViewLoadingView.setVisibility(View.GONE);
// Show the ListView Loading View and set it to refresh.
listViewLoadingView.setVisibility(View.VISIBLE);
listViewLoadingView.refreshing();
if (doScroll) {
// We need to disable the automatic visibility changes for now
disableLoadingLayoutVisibilityChanges();
// We scroll slightly so that the ListView's header/footer is at the
// same Y position as our normal header/footer
setHeaderScroll(scrollToY);
// Make sure the ListView is scrolled to show the loading
// header/footer
mRefreshableView.setSelection(selection);
// Smooth scroll as normal
smoothScrollTo(0);
}
}
#Override
protected void onReset() {
/**
* If the extras are not enabled, just call up to super and return.
*/
if (!mListViewExtrasEnabled) {
super.onReset();
return;
}
final LoadingLayout originalLoadingLayout, listViewLoadingLayout;
final int scrollToHeight, selection;
final boolean scrollLvToEdge;
switch (getCurrentMode()) {
case MANUAL_REFRESH_ONLY:
case PULL_FROM_END:
originalLoadingLayout = getFooterLayout();
listViewLoadingLayout = mFooterLoadingView;
selection = mRefreshableView.getCount() - 1;
scrollToHeight = getFooterSize();
scrollLvToEdge = Math.abs(mRefreshableView.getLastVisiblePosition() - selection) <= 1;
break;
case PULL_FROM_START:
default:
originalLoadingLayout = getHeaderLayout();
listViewLoadingLayout = mHeaderLoadingView;
scrollToHeight = -getHeaderSize();
selection = 0;
scrollLvToEdge = Math.abs(mRefreshableView.getFirstVisiblePosition() - selection) <= 1;
break;
}
// If the ListView header loading layout is showing, then we need to
// flip so that the original one is showing instead
if (listViewLoadingLayout.getVisibility() == View.VISIBLE) {
// Set our Original View to Visible
originalLoadingLayout.showInvisibleViews();
// Hide the ListView Header/Footer
listViewLoadingLayout.setVisibility(View.GONE);
/**
* Scroll so the View is at the same Y as the ListView
* header/footer, but only scroll if: we've pulled to refresh, it's
* positioned correctly
*/
if (scrollLvToEdge && getState() != State.MANUAL_REFRESHING) {
mRefreshableView.setSelection(selection);
setHeaderScroll(scrollToHeight);
}
}
// Finally, call up to super
super.onReset();
}
#Override
protected LoadingLayoutProxy createLoadingLayoutProxy(final boolean includeStart, final boolean includeEnd) {
LoadingLayoutProxy proxy = super.createLoadingLayoutProxy(includeStart, includeEnd);
if (mListViewExtrasEnabled) {
final Mode mode = getMode();
if (includeStart && mode.showHeaderLoadingLayout()) {
proxy.addLayout(mHeaderLoadingView);
}
if (includeEnd && mode.showFooterLoadingLayout()) {
proxy.addLayout(mFooterLoadingView);
}
}
return proxy;
}
protected ListView createListView(Context context, AttributeSet attrs) {
final ListView lv;
if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
lv = new InternalListViewSDK9(context, attrs);
} else {
lv = new InternalListView(context, attrs);
}
return lv;
}
#Override
protected ListView createRefreshableView(Context context, AttributeSet attrs) {
ListView lv = createListView(context, attrs);
// Set it to this so it can be used in ListActivity/ListFragment
lv.setId(android.R.id.list);
return lv;
}
#Override
protected void handleStyledAttributes(TypedArray a) {
super.handleStyledAttributes(a);
mListViewExtrasEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true);
if (mListViewExtrasEnabled) {
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL);
// Create Loading Views ready for use later
FrameLayout frame = new FrameLayout(getContext());
mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a);
mHeaderLoadingView.setVisibility(View.GONE);
frame.addView(mHeaderLoadingView, lp);
mRefreshableView.addHeaderView(frame, null, false);
mLvFooterLoadingFrame = new FrameLayout(getContext());
mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a);
mFooterLoadingView.setVisibility(View.GONE);
mLvFooterLoadingFrame.addView(mFooterLoadingView, lp);
/**
* If the value for Scrolling While Refreshing hasn't been
* explicitly set via XML, enable Scrolling While Refreshing.
*/
if (!a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) {
setScrollingWhileRefreshingEnabled(true);
}
}
}
#TargetApi(9)
final class InternalListViewSDK9 extends InternalListView {
public InternalListViewSDK9(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
// Does all of the hard work...
OverscrollHelper.overScrollBy(PullToRefreshListView.this, deltaX, scrollX, deltaY, scrollY, isTouchEvent);
return returnValue;
}
}
protected class InternalListView extends ListView implements EmptyViewMethodAccessor {
private boolean mAddedLvFooter = false;
public InternalListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void dispatchDraw(Canvas canvas) {
/**
* This is a bit hacky, but Samsung's ListView has got a bug in it
* when using Header/Footer Views and the list is empty. This masks
* the issue so that it doesn't cause an FC. See Issue #66.
*/
try {
super.dispatchDraw(canvas);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
/**
* This is a bit hacky, but Samsung's ListView has got a bug in it
* when using Header/Footer Views and the list is empty. This masks
* the issue so that it doesn't cause an FC. See Issue #66.
*/
try {
return super.dispatchTouchEvent(ev);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
return false;
}
}
#Override
public void setAdapter(ListAdapter adapter) {
// Add the Footer View at the last possible moment
if (null != mLvFooterLoadingFrame && !mAddedLvFooter) {
addFooterView(mLvFooterLoadingFrame, null, false);
mAddedLvFooter = true;
}
super.setAdapter(adapter);
}
#Override
public void setEmptyView(View emptyView) {
PullToRefreshListView.this.setEmptyView(emptyView);
}
#Override
public void setEmptyViewInternal(View emptyView) {
super.setEmptyView(emptyView);
}
}
//add jazzy listview
/**
* Sets the desired transition effect.
*
* #param transitionEffect The non-bundled transition provided by the client.
*/
public void setTransitionEffect(JazzyEffect transitionEffect) {
mHelper.setTransitionEffect(transitionEffect);
}
#Override
public void setOnScrollListener(OnScrollListener l) {
mHelper.setOnScrollListener(l);
}
private JazzyHelper init(Context context, AttributeSet attrs) {
JazzyHelper helper = new JazzyHelper(context, attrs);
super.setOnScrollListener(helper);
return helper;
}
}
I hava verify the code.wish can help you.
Here is a demo,you can try it :
https://github.com/XIONGDEYI/PullToRefreshListViewAndJazzyListView