Is there some way to implement drag and drop functionality in API 8 Android?
Looked here, but it appears after API 11.
I need to drag view from one LinearLayout to another. Ho can i implement this on API 8?
Try like this
import android.app.Activity;
import android.content.ClipData;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
ListView source = null;
TextView target1 = null;
TextView target2 = null;
TextView target3 = null;
String[] listItems = {"Samsung", "Apple", "Google", "Nokia"};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
source = (ListView)findViewById(R.id.dragSource);
target1 = (TextView) findViewById(R.id.dragTarget1);
target2 = (TextView) findViewById(R.id.dragTarget2);
target3 = (TextView) findViewById(R.id.dragTarget3);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listItems);
source.setAdapter(adapter);
// Start Drag
source.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String item = listItems[position];
ClipData data = ClipData.newPlainText("DragIt", item);
source.startDrag(data, new MyShadowBuilder(view), null, 0);
}
});
// Handle Drag
target1.setOnDragListener(new MyDragListener());
target2.setOnDragListener(new MyDragListener());
target3.setOnDragListener(new MyDragListener());
}
// Drag Shadow
private class MyShadowBuilder extends DragShadowBuilder {
public MyShadowBuilder(View v) {
super(v);
}
#Override
public void onDrawShadow(Canvas canvas) {
// Set Drag image background or anything you want
int width = getView().getWidth();
int height = getView().getHeight();
Paint paint = new Paint();
paint.setColor(0x55858585);
canvas.drawRect(new Rect(0, 0, width, height), paint);
super.onDrawShadow(canvas);
}
#Override
public void onProvideShadowMetrics(Point shadowSize,
Point shadowTouchPoint) {
int width = getView().getWidth();
int height = getView().getHeight();
shadowSize.set(width, height);
shadowTouchPoint.set(width/2, height);
}
}
// Drag Listener
private class MyDragListener implements OnDragListener {
private final int DEFAULT_BG_COLOR = 0xFF858585;
private final int HIGHLIGHT_BG_COLOR = 0xFF0000FF;
#Override
public boolean onDrag(View v, DragEvent event) {
if(event.getAction() == DragEvent.ACTION_DRAG_ENTERED) {
v.setBackgroundColor(HIGHLIGHT_BG_COLOR);
}
else if(event.getAction() == DragEvent.ACTION_DRAG_EXITED) {
v.setBackgroundColor(DEFAULT_BG_COLOR);
}
else if(event.getAction() == DragEvent.ACTION_DROP) {
// Perform drop
ClipData clip = event.getClipData();
ClipData.Item item = clip.getItemAt(0);
String text = item.getText().toString();
((TextView) v).setText(text);
v.setBackgroundColor(DEFAULT_BG_COLOR);
}
// Send true to listen All Drag Events.
return true;
}
}
}
XML is like:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="161dp"
android:layout_height="fill_parent"
android:background="#FF858585"
android:orientation="vertical" >
<TextView
android:id="#+id/dragTarget1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.04"
android:text="Drop Here"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/dragTarget2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.04"
android:text="Drop Here"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/dragTarget3"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.04"
android:text="Drop Here"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/dragSource"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
Try another approach by using WindowManager :
package com.example.cooldraganddrop;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ImageView;
public class CoolDragAndDropGridView extends SpanVariableGridView implements `View.OnTouchListener {`
private static final int ITEM_HOVER_DELAY = 450;
private int mDragPointX;
private int mDragPointY;
private int mDragOffsetX;
private int mDragOffsetY;
private int mDragPosition = AdapterView.INVALID_POSITION;
private int mDropPosition = AdapterView.INVALID_POSITION;
private int mCurrentPosition = AdapterView.INVALID_POSITION;
private Runnable mDelayedOnDragRunnable = null;
ScrollingStrategy mScrollingStrategy = null;
WindowManager mWindowManager = null;
WindowManager.LayoutParams mWindowParams = null;
private ImageView mDragImageView = null;
private boolean mDragAndDropStarted = false;
private DragAndDropListener mDragAndDropListener = null;
private OnTrackTouchEventsListener mOnTrackTouchEventsListener = null;
public static interface OnTrackTouchEventsListener {
void trackTouchEvents(final MotionEvent motionEvent);
};
public static interface DragAndDropListener {
void onDragItem(int from);
void onDraggingItem(int from, int to);
void onDropItem(int from, int to);
boolean isDragAndDropEnabled(int position);
}
public CoolDragAndDropGridView(Context context) {
super(context);
initialize();
}
public CoolDragAndDropGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize();
}
public CoolDragAndDropGridView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
private void initialize() {
setOnTouchListener(this);
setChildrenDrawingOrderEnabled(true);
}
public void startDragAndDrop() {
mDragAndDropStarted = true;
}
public void setDragAndDropListener(DragAndDropListener dragAndDropListener) {
mDragAndDropListener = dragAndDropListener;
}
private void destroyDragImageView() {
if (mDragImageView != null) {
mWindowManager.removeView(mDragImageView);
BitmapDrawable bitmapDrawable = (BitmapDrawable) mDragImageView.getDrawable();
if (bitmapDrawable != null) {
final Bitmap bitmap = bitmapDrawable.getBitmap();
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
}
mDragImageView.setImageDrawable(null);
mDragImageView = null;
}
}
private ImageView createDragImageView(final View v, final int x, final int y) {
v.destroyDrawingCache();
v.setDrawingCacheEnabled(true);
Bitmap bm = Bitmap.createBitmap(v.getDrawingCache());
mDragPointX = x - v.getLeft();
mDragPointY = y - v.getTop();
mWindowParams = new WindowManager.LayoutParams();
mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
mWindowParams.x = x - mDragPointX + mDragOffsetX;
mWindowParams.y = y - mDragPointY + mDragOffsetY;
mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
mWindowParams.format = PixelFormat.TRANSLUCENT;
mWindowParams.alpha = 0.7f;
mWindowParams.windowAnimations = 0;
ImageView iv = new ImageView(getContext());
iv.setBackgroundColor(Color.parseColor("#ff555555"));
iv.setImageBitmap(bm);
mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);// "window"
mWindowManager.addView(iv, mWindowParams);
return iv;
}
private void startDrag(final int x, final int y) {
final View v = getChildAt(mDragPosition);
destroyDragImageView();
mDragImageView = createDragImageView(v, x, y);
v.setVisibility(View.INVISIBLE);
if (mDragAndDropListener != null) {
mDragAndDropListener.onDragItem(mDragPosition);
}
}
#Override
protected int getChildDrawingOrder(int childCount, int i) {
if (mCurrentPosition == -1)
return i;
else if (i == childCount - 1)
return mCurrentPosition;
else if (i >= mCurrentPosition)
return i + 1;
return i;
}
private void onDrop() {
destroyDragImageView();
removeCallbacks(mDelayedOnDragRunnable);
View v = getChildAt(mDropPosition);
v.setVisibility(View.VISIBLE);
v.clearAnimation();
if (mDragAndDropListener != null && mDropPosition != AdapterView.INVALID_POSITION) {
mDragAndDropListener.onDropItem(mDragPosition, mDropPosition);
}
mDragPosition = mDropPosition = mCurrentPosition = AdapterView.INVALID_POSITION;
mDragAndDropStarted = false;
}
public void setScrollingStrategy(ScrollingStrategy scrollingStrategy) {
mScrollingStrategy = scrollingStrategy;
}
private void onDrag(final int x, final int y) {
if (mScrollingStrategy != null && mScrollingStrategy.performScrolling(x, y, this)) {
removeCallbacks(mDelayedOnDragRunnable);
return;
}
final int tempDropPosition = pointToPosition(mCurrentPosition, x, y);
if (mDragAndDropListener != null && mDropPosition != tempDropPosition && tempDropPosition != AdapterView.INVALID_POSITION) {
removeCallbacks(mDelayedOnDragRunnable);
if (mDragAndDropListener.isDragAndDropEnabled(tempDropPosition)) {
mDropPosition = tempDropPosition;
mDelayedOnDragRunnable = new Runnable() {
#Override
public void run() {
mDragAndDropListener.onDraggingItem(mCurrentPosition, tempDropPosition);
performDragAndDropSwapping(mCurrentPosition, tempDropPosition);
final int nextDropPosition = pointToPosition(tempDropPosition, x, y);
if (nextDropPosition == AdapterView.INVALID_POSITION) {
mCurrentPosition = mDropPosition = tempDropPosition;
}
}
};
postDelayed(mDelayedOnDragRunnable, ITEM_HOVER_DELAY);
} else {
mDropPosition = mDragPosition;
}
}
if (mDragImageView != null) {
mWindowParams.x = x - mDragPointX + mDragOffsetX;
mWindowParams.y = y - mDragPointY + mDragOffsetY;
mWindowManager.updateViewLayout(mDragImageView, mWindowParams);
}
}
public void setOnTrackTouchEventListener(OnTrackTouchEventsListener onTrackTouchEventsListener) {
mOnTrackTouchEventsListener = onTrackTouchEventsListener;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mOnTrackTouchEventsListener != null) {
mOnTrackTouchEventsListener.trackTouchEvents(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
if (mDragAndDropListener != null && mDragAndDropStarted) {
mDragAndDropStarted = false;
getParent().requestDisallowInterceptTouchEvent(true);
return launchDragAndDrop(event);
}
break;
default:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mDragAndDropStarted = false;
getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return super.onInterceptTouchEvent(event);
}
private boolean launchDragAndDrop(final MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
mCurrentPosition = mDragPosition = mDropPosition = pointToPosition(mDragPosition, x, y);
if (mDragPosition != AdapterView.INVALID_POSITION && mDragAndDropListener.isDragAndDropEnabled(mDragPosition)) {
mDragOffsetX = (int) (event.getRawX() - x);
mDragOffsetY = (int) (event.getRawY() - y);
startDrag(x, y);
return true;
}
return false;
}
#Override
public boolean onTouch(View view, MotionEvent event) {
if (mDragPosition != AdapterView.INVALID_POSITION && mDragImageView != null) {
final int x = (int) event.getX();
final int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
mDragOffsetX = (int) (event.getRawX() - x);
mDragOffsetY = (int) (event.getRawY() - y);
onDrag(x, y);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
onDrop();
resetLongClickTransition();
getParent().requestDisallowInterceptTouchEvent(false);
return false;
default:
}
return true;
}
return false;
}
}
Sample using this approach of a drag and drop is here
Related
In this picture, you can see a CardView where each item is displayed one at a time. I have implemented a touch functionality that scrolls through the dataset. I would now like to implement the functionality of choosing an item at random. Here is where the CardView is set:
package com.chiemy.cardview.view;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.AccelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ListAdapter;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.view.ViewHelper;
import com.nineoldandroids.view.ViewPropertyAnimator;
/**
* #author chiemy
*
*/
public class CardView extends FrameLayout {
private static final int ITEM_SPACE = 40;
private static final int DEF_MAX_VISIBLE = 4;
private int mMaxVisible = DEF_MAX_VISIBLE;
private int itemSpace = ITEM_SPACE;
private float mTouchSlop;
private ListAdapter mListAdapter;
private int mNextAdapterPosition;
private SparseArray<View> viewHolder = new SparseArray<View>();
private OnCardClickListener mListener;
private int topPosition;
private Rect topRect;
public interface OnCardClickListener {
void onCardClick(View view, int position);
}
public CardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CardView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CardView(Context context) {
super(context);
init();
}
private void init() {
topRect = new Rect();
ViewConfiguration con = ViewConfiguration.get(getContext());
mTouchSlop = con.getScaledTouchSlop();
}
public void setMaxVisibleCount(int count) {
mMaxVisible = count;
}
public int getMaxVisibleCount() {
return mMaxVisible;
}
public void setItemSpace(int itemSpace) {
this.itemSpace = itemSpace;
}
public int getItemSpace() {
return itemSpace;
}
public ListAdapter getAdapter() {
return mListAdapter;
}
public void setAdapter(ListAdapter adapter) {
if (mListAdapter != null) {
mListAdapter.unregisterDataSetObserver(mDataSetObserver);
}
mNextAdapterPosition = 0;
mListAdapter = adapter;
adapter.registerDataSetObserver(mDataSetObserver);
removeAllViews();
ensureFull();
}
public void setOnCardClickListener(OnCardClickListener listener) {
mListener = listener;
}
private void ensureFull() {
while (mNextAdapterPosition < mListAdapter.getCount()
&& getChildCount() < mMaxVisible) {
int index = mNextAdapterPosition % mMaxVisible;
View convertView = viewHolder.get(index);
final View view = mListAdapter.getView(mNextAdapterPosition,
convertView, this);
view.setOnClickListener(null);
viewHolder.put(index, view);
index = Math.min(mNextAdapterPosition, mMaxVisible - 1);
ViewHelper.setScaleX(view,((mMaxVisible - index - 1) / (float) mMaxVisible) * 0.2f + 0.8f);
int topMargin = (mMaxVisible - index - 1) * itemSpace;
ViewHelper.setTranslationY(view, topMargin);
ViewHelper.setAlpha(view, mNextAdapterPosition == 0 ? 1 : 0.5f);
LayoutParams params = (LayoutParams) view.getLayoutParams();
if (params == null) {
params = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
}
addViewInLayout(view, 0, params);
mNextAdapterPosition += 1;
}
// requestLayout();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int childCount = getChildCount();
int maxHeight = 0;
int maxWidth = 0;
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
int height = child.getMeasuredHeight();
int width = child.getMeasuredWidth();
if (height > maxHeight) {
maxHeight = height;
}
if (width > maxWidth) {
maxWidth = width;
}
}
int desireWidth = widthSize;
int desireHeight = heightSize;
if (widthMode == MeasureSpec.AT_MOST) {
desireWidth = maxWidth + getPaddingLeft() + getPaddingRight();
}
if (heightMode == MeasureSpec.AT_MOST) {
desireHeight = maxHeight + (mMaxVisible - 1) * itemSpace + getPaddingTop() + getPaddingBottom();
}
setMeasuredDimension(desireWidth, desireHeight);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
View topView = getChildAt(getChildCount() - 1);
if (topView != null) {
topView.setOnClickListener(listener);
}
}
float downX, downY;
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
if (goDown()) {
downY = -1;
}
break;
}
return super.onTouchEvent(event);
}
/**
* 下移所有视图
*/
private boolean goDown() {
final View topView = getChildAt(getChildCount() - 1);
if(!topView.isEnabled()){
return false;
}
// topView.getHitRect(topRect); 在4.3以前有bug,用以下方法代替
topRect = getHitRect(topRect, topView);
// 如果按下的位置不在顶部视图上,则不移动
if (!topRect.contains((int) downX, (int) downY)) {
return false;
}
topView.setEnabled(false);
ViewPropertyAnimator anim = ViewPropertyAnimator
.animate(topView)
.translationY(
ViewHelper.getTranslationY(topView)
+ topView.getHeight()).alpha(0).scaleX(1)
.setListener(null).setDuration(200);
anim.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
topView.setEnabled(true);
removeView(topView);
ensureFull();
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View view = getChildAt(i);
float scaleX = ViewHelper.getScaleX(view)
+ ((float) 1 / mMaxVisible) * 0.2f;
float tranlateY = ViewHelper.getTranslationY(view)
+ itemSpace;
if (i == count - 1) {
bringToTop(view);
} else {
if ((count == mMaxVisible && i != 0)
|| count < mMaxVisible) {
ViewPropertyAnimator
.animate(view)
.translationY(tranlateY)
.setInterpolator(
new AccelerateInterpolator())
.setListener(null).scaleX(scaleX)
.setDuration(200);
}
}
}
}
});
return true;
}
private void bringToTop(final View view) {
topPosition++;
float scaleX = ViewHelper.getScaleX(view) + ((float) 1 / mMaxVisible)
* 0.2f;
float tranlateY = ViewHelper.getTranslationY(view) + itemSpace;
ViewPropertyAnimator.animate(view).translationY(tranlateY)
.scaleX(scaleX).setDuration(200).alpha(1)
.setInterpolator(new AccelerateInterpolator());
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
float currentY = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = ev.getX();
downY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
float distance = currentY - downY;
if (distance > mTouchSlop) {
return true;
}
break;
}
return false;
}
public static Rect getHitRect(Rect rect, View child) {
rect.left = child.getLeft();
rect.right = child.getRight();
rect.top = (int) (child.getTop() + ViewHelper.getTranslationY(child));
rect.bottom = (int) (child.getBottom() + ViewHelper
.getTranslationY(child));
return rect;
}
private final DataSetObserver mDataSetObserver = new DataSetObserver() {
#Override
public void onChanged() {
super.onChanged();
}
#Override
public void onInvalidated() {
super.onInvalidated();
}
};
private OnClickListener listener = new OnClickListener() {
#Override
public void onClick(View v) {
if (mListener != null) {
mListener.onCardClick(v, topPosition);
}
}
};
}
Here is my CardView adapter class:
package com.chiemy.cardview.view;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.chiemy.cardview.R;
public abstract class CardAdapter<T> extends BaseCardAdapter {
private final Context mContext;
private ArrayList<T> mData;
public CardAdapter(Context context) {
mContext = context;
mData = new ArrayList<T>();
}
public CardAdapter(Context context, Collection<? extends T> items) {
mContext = context;
mData = new ArrayList<T>(items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
FrameLayout wrapper = (FrameLayout) convertView;
View cardView;
View convertedCardView;
if (wrapper == null) {
wrapper = new FrameLayout(mContext);
wrapper.setBackgroundResource(R.drawable.card_background_shadow);
cardView = getCardView(position, null, wrapper);
wrapper.addView(cardView);
} else {
cardView = wrapper.getChildAt(0);
convertedCardView = getCardView(position, cardView, wrapper);
wrapper.removeView(cardView);
wrapper.addView(convertedCardView);
if (convertedCardView != cardView) {
}
}
return wrapper;
}
protected abstract View getCardView(int position, View convertView, ViewGroup parent);
public void addAll(List<T> items){
mData.addAll(items);
}
#Override
public T getItem(int position) {
return mData.get(position);
}
#Override
public int getCount() {
return mData.size();
}
#Override
public long getItemId(int position) {
return getItem(position).hashCode();
}
public Context getContext() {
return mContext;
}
public void clear(){
if(mData != null){
mData.clear();
}
}
}
Any suggestions on how to achieve this?
To randomise an ArrayList<>, in your case, this would be the shuffling solution, you can use this code:
long seed = System.nanoTime();
Collections.shuffle(list_of_items, new Random(seed));
You will need to set the ArrayList<> back to the CardView and your items will be randomly shuffled. To retrieve a random item, visit this page to learn about getting a random item from an ArrayList<>. See how you go and ask for more help if needed.
I am using a floating action button in my activity. I have created a related layout with a black opacity background. I want it to appear when the floating action button is clicked. The relative layout will appear behind the action button to make it look prominent.
Here is my xml layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fab="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.paaltao.activity.HomeActivity">
<include
android:id="#+id/app_bar"
layout="#layout/app_bar" />
<it.neokree.materialtabs.MaterialTabHost
android:id="#+id/materialTabHost"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_below="#+id/app_bar"
app:accentColor="#color/greenMaterial"
app:hasIcons="true"
app:primaryColor="#color/primaryColor"
app:textColor="#color/white" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/materialTabHost" />
<RelativeLayout
android:id="#+id/white_opacity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/materialTabHost"
android:background="#color/black80"
android:visibility="gone" />
<com.paaltao.classes.FloatingActionsMenu
android:id="#+id/multiple_actions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_gravity="end"
fab:fab_addButtonColorPressed="#color/white_pressed"
fab:fab_addButtonPlusIconColor="#color/white"
fab:fab_labelStyle="#style/menu_labels_style"
app:fab_addButtonColorNormal="#color/primaryColor">
<com.paaltao.classes.FloatingActionButton
android:id="#+id/action_b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
fab:fab_colorNormal="#color/white"
fab:fab_colorPressed="#color/white_pressed"
fab:fab_title="Action B" />
</com.paaltao.classes.FloatingActionsMenu>
</RelativeLayout>
I am basically trying to set visibility of the relative layout to View.VISIBLE in the floating action menu class which extends a view group. Now I am getting null pointer exception when I am setting the visibility as View.VISIBLE in the button's onClick event.
Here is my Java Code :
package com.paaltao.classes;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.paaltao.R;
import java.util.zip.Inflater;
public class FloatingActionsMenu extends ViewGroup {
public static final int EXPAND_UP = 0;
public static final int EXPAND_DOWN = 1;
public static final int EXPAND_LEFT = 2;
public static final int EXPAND_RIGHT = 3;
private static final int ANIMATION_DURATION = 300;
private static final float COLLAPSED_PLUS_ROTATION = 0f;
private static final float EXPANDED_PLUS_ROTATION = 90f + 45f;
private int mAddButtonPlusColor;
private int mAddButtonColorNormal;
private int mAddButtonColorPressed;
private int mAddButtonSize;
private boolean mAddButtonStrokeVisible;
private int mExpandDirection;
private int mButtonSpacing;
private int mLabelsMargin;
private int mLabelsVerticalOffset;
private boolean mExpanded;
private AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
private AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
private AddFloatingActionButton mAddButton;
private RotatingDrawable mRotatingDrawable;
private int mMaxButtonWidth;
private int mMaxButtonHeight;
private int mLabelsStyle;
private int mButtonsCount;
private OnFloatingActionsMenuUpdateListener mListener;
private RelativeLayout whiteOverlay;
public interface OnFloatingActionsMenuUpdateListener {
void onMenuExpanded();
void onMenuCollapsed();
}
public FloatingActionsMenu(Context context) {
this(context, null);
}
public FloatingActionsMenu(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public FloatingActionsMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attributeSet) {
mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing) - getResources().getDimension(R.dimen.fab_shadow_radius) - getResources().getDimension(R.dimen.fab_shadow_offset));
mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin);
mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset);
TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0);
mAddButtonPlusColor = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonPlusIconColor, getColor(android.R.color.white));
mAddButtonColorNormal = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorNormal, getColor(android.R.color.holo_blue_dark));
mAddButtonColorPressed = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorPressed, getColor(android.R.color.holo_blue_light));
mAddButtonSize = attr.getInt(R.styleable.FloatingActionsMenu_fab_addButtonSize, FloatingActionButton.SIZE_NORMAL);
mAddButtonStrokeVisible = attr.getBoolean(R.styleable.FloatingActionsMenu_fab_addButtonStrokeVisible, true);
mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP);
mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0);
attr.recycle();
if (mLabelsStyle != 0 && expandsHorizontally()) {
throw new IllegalStateException("Action labels in horizontal expand orientation is not supported.");
}
createAddButton(context);
}
public void setOnFloatingActionsMenuUpdateListener(OnFloatingActionsMenuUpdateListener listener) {
mListener = listener;
}
private boolean expandsHorizontally() {
return mExpandDirection == EXPAND_LEFT || mExpandDirection == EXPAND_RIGHT;
}
private static class RotatingDrawable extends LayerDrawable {
public RotatingDrawable(Drawable drawable) {
super(new Drawable[] { drawable });
}
private float mRotation;
#SuppressWarnings("UnusedDeclaration")
public float getRotation() {
return mRotation;
}
#SuppressWarnings("UnusedDeclaration")
public void setRotation(float rotation) {
mRotation = rotation;
invalidateSelf();
}
#Override
public void draw(Canvas canvas) {
canvas.save();
canvas.rotate(mRotation, getBounds().centerX(), getBounds().centerY());
super.draw(canvas);
canvas.restore();
}
}
private void createAddButton(Context context) {
mAddButton = new AddFloatingActionButton(context) {
#Override
void updateBackground() {
mPlusColor = mAddButtonPlusColor;
mColorNormal = mAddButtonColorNormal;
mColorPressed = mAddButtonColorPressed;
mStrokeVisible = mAddButtonStrokeVisible;
super.updateBackground();
}
#Override
Drawable getIconDrawable() {
final RotatingDrawable rotatingDrawable = new RotatingDrawable(super.getIconDrawable());
mRotatingDrawable = rotatingDrawable;
final OvershootInterpolator interpolator = new OvershootInterpolator();
final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION);
final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION);
collapseAnimator.setInterpolator(interpolator);
expandAnimator.setInterpolator(interpolator);
mExpandAnimation.play(expandAnimator);
mCollapseAnimation.play(collapseAnimator);
return rotatingDrawable;
}
};
mAddButton.setId(R.id.fab_expand_menu_button);
mAddButton.setSize(mAddButtonSize);
mAddButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
toggle();
// updateBackground();
}
});
addView(mAddButton, super.generateDefaultLayoutParams());
}
// public void updateBackground(){
// whiteOverlay = (RelativeLayout)findViewById(R.id.white_opacity);
// whiteOverlay.setVisibility(View.VISIBLE);
// }
public void addButton(FloatingActionButton button) {
addView(button, mButtonsCount - 1);
mButtonsCount++;
if (mLabelsStyle != 0) {
createLabels();
}
}
public void removeButton(FloatingActionButton button) {
removeView(button.getLabelView());
removeView(button);
mButtonsCount--;
}
private int getColor(#ColorRes int id) {
return getResources().getColor(id);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
int width = 0;
int height = 0;
mMaxButtonWidth = 0;
mMaxButtonHeight = 0;
int maxLabelWidth = 0;
for (int i = 0; i < mButtonsCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
switch (mExpandDirection) {
case EXPAND_UP:
case EXPAND_DOWN:
mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());
height += child.getMeasuredHeight();
break;
case EXPAND_LEFT:
case EXPAND_RIGHT:
width += child.getMeasuredWidth();
mMaxButtonHeight = Math.max(mMaxButtonHeight, child.getMeasuredHeight());
break;
}
if (!expandsHorizontally()) {
TextView label = (TextView) child.getTag(R.id.fab_label);
if (label != null) {
maxLabelWidth = Math.max(maxLabelWidth, label.getMeasuredWidth());
}
}
}
if (!expandsHorizontally()) {
width = mMaxButtonWidth + (maxLabelWidth > 0 ? maxLabelWidth + mLabelsMargin : 0);
} else {
height = mMaxButtonHeight;
}
switch (mExpandDirection) {
case EXPAND_UP:
case EXPAND_DOWN:
height += mButtonSpacing * (getChildCount() - 1);
height = adjustForOvershoot(height);
break;
case EXPAND_LEFT:
case EXPAND_RIGHT:
width += mButtonSpacing * (getChildCount() - 1);
width = adjustForOvershoot(width);
break;
}
setMeasuredDimension(width, height);
}
private int adjustForOvershoot(int dimension) {
return dimension * 12 / 10;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
switch (mExpandDirection) {
case EXPAND_UP:
case EXPAND_DOWN:
boolean expandUp = mExpandDirection == EXPAND_UP;
int addButtonY = expandUp ? b - t - mAddButton.getMeasuredHeight() : 0;
// Ensure mAddButton is centered on the line where the buttons should be
int addButtonLeft = r - l - mMaxButtonWidth + (mMaxButtonWidth - mAddButton.getMeasuredWidth()) / 2;
mAddButton.layout(addButtonLeft, addButtonY, addButtonLeft + mAddButton.getMeasuredWidth(), addButtonY + mAddButton.getMeasuredHeight());
int labelsRight = r - l - mMaxButtonWidth - mLabelsMargin;
int nextY = expandUp ?
addButtonY - mButtonSpacing :
addButtonY + mAddButton.getMeasuredHeight() + mButtonSpacing;
for (int i = mButtonsCount - 1; i >= 0; i--) {
final View child = getChildAt(i);
if (child == mAddButton || child.getVisibility() == GONE) continue;
int childX = addButtonLeft + (mAddButton.getMeasuredWidth() - child.getMeasuredWidth()) / 2;
int childY = expandUp ? nextY - child.getMeasuredHeight() : nextY;
child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight());
float collapsedTranslation = addButtonY - childY;
float expandedTranslation = 0f;
child.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation);
child.setAlpha(mExpanded ? 1f : 0f);
LayoutParams params = (LayoutParams) child.getLayoutParams();
params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);
params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);
params.setAnimationsTarget(child);
View label = (View) child.getTag(R.id.fab_label);
if (label != null) {
int labelLeft = labelsRight - label.getMeasuredWidth();
int labelTop = childY - mLabelsVerticalOffset + (child.getMeasuredHeight() - label.getMeasuredHeight()) / 2;
label.layout(labelLeft, labelTop, labelsRight, labelTop + label.getMeasuredHeight());
label.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation);
label.setAlpha(mExpanded ? 1f : 0f);
LayoutParams labelParams = (LayoutParams) label.getLayoutParams();
labelParams.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);
labelParams.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);
labelParams.setAnimationsTarget(label);
}
nextY = expandUp ?
childY - mButtonSpacing :
childY + child.getMeasuredHeight() + mButtonSpacing;
}
break;
case EXPAND_LEFT:
case EXPAND_RIGHT:
boolean expandLeft = mExpandDirection == EXPAND_LEFT;
int addButtonX = expandLeft ? r - l - mAddButton.getMeasuredWidth() : 0;
// Ensure mAddButton is centered on the line where the buttons should be
int addButtonTop = b - t - mMaxButtonHeight + (mMaxButtonHeight - mAddButton.getMeasuredHeight()) / 2;
mAddButton.layout(addButtonX, addButtonTop, addButtonX + mAddButton.getMeasuredWidth(), addButtonTop + mAddButton.getMeasuredHeight());
int nextX = expandLeft ?
addButtonX - mButtonSpacing :
addButtonX + mAddButton.getMeasuredWidth() + mButtonSpacing;
for (int i = mButtonsCount - 1; i >= 0; i--) {
final View child = getChildAt(i);
if (child == mAddButton || child.getVisibility() == GONE) continue;
int childX = expandLeft ? nextX - child.getMeasuredWidth() : nextX;
int childY = addButtonTop + (mAddButton.getMeasuredHeight() - child.getMeasuredHeight()) / 2;
child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight());
float collapsedTranslation = addButtonX - childX;
float expandedTranslation = 0f;
child.setTranslationX(mExpanded ? expandedTranslation : collapsedTranslation);
child.setAlpha(mExpanded ? 1f : 0f);
LayoutParams params = (LayoutParams) child.getLayoutParams();
params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);
params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);
params.setAnimationsTarget(child);
nextX = expandLeft ?
childX - mButtonSpacing :
childX + child.getMeasuredWidth() + mButtonSpacing;
}
break;
}
}
#Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(super.generateDefaultLayoutParams());
}
#Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(super.generateLayoutParams(attrs));
}
#Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(super.generateLayoutParams(p));
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return super.checkLayoutParams(p);
}
private static Interpolator sExpandInterpolator = new OvershootInterpolator();
private static Interpolator sCollapseInterpolator = new DecelerateInterpolator(3f);
private static Interpolator sAlphaExpandInterpolator = new DecelerateInterpolator();
private class LayoutParams extends ViewGroup.LayoutParams {
private ObjectAnimator mExpandDir = new ObjectAnimator();
private ObjectAnimator mExpandAlpha = new ObjectAnimator();
private ObjectAnimator mCollapseDir = new ObjectAnimator();
private ObjectAnimator mCollapseAlpha = new ObjectAnimator();
private boolean animationsSetToPlay;
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
mExpandDir.setInterpolator(sExpandInterpolator);
mExpandAlpha.setInterpolator(sAlphaExpandInterpolator);
mCollapseDir.setInterpolator(sCollapseInterpolator);
mCollapseAlpha.setInterpolator(sCollapseInterpolator);
mCollapseAlpha.setProperty(View.ALPHA);
mCollapseAlpha.setFloatValues(1f, 0f);
mExpandAlpha.setProperty(View.ALPHA);
mExpandAlpha.setFloatValues(0f, 1f);
switch (mExpandDirection) {
case EXPAND_UP:
case EXPAND_DOWN:
mCollapseDir.setProperty(View.TRANSLATION_Y);
mExpandDir.setProperty(View.TRANSLATION_Y);
break;
case EXPAND_LEFT:
case EXPAND_RIGHT:
mCollapseDir.setProperty(View.TRANSLATION_X);
mExpandDir.setProperty(View.TRANSLATION_X);
break;
}
}
public void setAnimationsTarget(View view) {
mCollapseAlpha.setTarget(view);
mCollapseDir.setTarget(view);
mExpandAlpha.setTarget(view);
mExpandDir.setTarget(view);
// Now that the animations have targets, set them to be played
if (!animationsSetToPlay) {
mCollapseAnimation.play(mCollapseAlpha);
mCollapseAnimation.play(mCollapseDir);
mExpandAnimation.play(mExpandAlpha);
mExpandAnimation.play(mExpandDir);
animationsSetToPlay = true;
}
}
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
bringChildToFront(mAddButton);
mButtonsCount = getChildCount();
if (mLabelsStyle != 0) {
createLabels();
}
}
private void createLabels() {
Context context = new ContextThemeWrapper(getContext(), mLabelsStyle);
for (int i = 0; i < mButtonsCount; i++) {
FloatingActionButton button = (FloatingActionButton) getChildAt(i);
String title = button.getTitle();
if (button == mAddButton || title == null ||
button.getTag(R.id.fab_label) != null) continue;
TextView label = new TextView(context);
label.setText(button.getTitle());
addView(label);
button.setTag(R.id.fab_label, label);
}
}
public void collapse() {
if (mExpanded) {
mExpanded = false;
mCollapseAnimation.start();
mExpandAnimation.cancel();
if (mListener != null) {
mListener.onMenuCollapsed();
}
}
}
public void toggle() {
if (mExpanded) {
collapse();
} else {
expand();
}
}
public void expand() {
if (!mExpanded) {
mExpanded = true;
mCollapseAnimation.cancel();
mExpandAnimation.start();
if (mListener != null) {
mListener.onMenuExpanded();
}
}
}
public boolean isExpanded() {
return mExpanded;
}
#Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState savedState = new SavedState(superState);
savedState.mExpanded = mExpanded;
return savedState;
}
#Override
public void onRestoreInstanceState(Parcelable state) {
if (state instanceof SavedState) {
SavedState savedState = (SavedState) state;
mExpanded = savedState.mExpanded;
if (mRotatingDrawable != null) {
mRotatingDrawable.setRotation(mExpanded ? EXPANDED_PLUS_ROTATION : COLLAPSED_PLUS_ROTATION);
}
super.onRestoreInstanceState(savedState.getSuperState());
} else {
super.onRestoreInstanceState(state);
}
}
public static class SavedState extends BaseSavedState {
public boolean mExpanded;
public SavedState(Parcelable parcel) {
super(parcel);
}
private SavedState(Parcel in) {
super(in);
mExpanded = in.readInt() == 1;
}
#Override
public void writeToParcel(#NonNull Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(mExpanded ? 1 : 0);
}
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
#Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
#Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
Please Help.
If I understand correctly, the code causing the problem is the one commented, otherwise this line :
whiteOverlay.setVisibility(View.VISIBLE);
You are trying to access your RelativeLayout (R.id.white_opacity) through your FloatingActionsMenu view :
whiteOverlay = (RelativeLayout)findViewById(R.id.white_opacity);
But R.id.white_opacity is a member of your HomeActivity view.
So it's normal that this line returns a null pointer since it doesn't have any member named like this.
Try do find a way to access your HomeActivity view and then call "findViewById()" on it.
If "context" is indeed this HomeActivity, then pass the argument to the updateBackground() method (or set context as a class member) and try somthing like that :
whiteOverlay = ((Activity)context).findViewById(R.id.white_opacity);
Regards.
I want to implement drag and drop of list-items in my application. I followed this, it works well for lists containing text only. I integrated lazy-list with images along with drag and drop. But, while I drag the item, the dragged item goes to actual position. The item below the dragged item gets removed from the list. After I take my fingers off, dragged item doesn't move to the place I wish. What is wrong with this code?
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.listviewdragginganimation.DynamicListView
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"/>
<Button
android:id="#+id/button1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Clear Cache"/>
</LinearLayout>
DynamicListView.Java:
package com.listviewdragginganimation;
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.util.Log;
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;
public class DynamicListView extends ListView {
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);
}
private AdapterView.OnItemLongClickListener mOnItemLongClickListener = new AdapterView.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;
}
};
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;
}
private void updateNeighborViewsForID(long itemID) {
int position = getPositionForID(itemID);
LazyAdapter adapter = ((LazyAdapter) 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();
LazyAdapter adapter = ((LazyAdapter) 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);
}
}
#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();
// Log.v("handle switch 1","1");
handleCellSwitch();
// Log.v("handle switch 2","2");
mIsMobileScrolling = false;
handleMobileCellScroll();
return false;
}
break;
case MotionEvent.ACTION_UP:
touchEventsEnded();
break;
case MotionEvent.ACTION_CANCEL:
touchEventsCancelled();
break;
case MotionEvent.ACTION_POINTER_UP:
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);
}
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;
}
Log.v("swapElements switch 1", "1");
Log.v("swapElements originalItem 1", originalItem + "");
Log.v("swapElements switchView 1", "" + switchView);
setCheeseList(MainActivity.mCheeseList);
Log.v("mCheeseList item", mCheeseList.get(originalItem));
swapElements(mCheeseList, originalItem,
getPositionForView(switchView));
Log.v("swapElements switch 2", "2");
// ((BaseAdapter) getAdapter()).notifyDataSetChanged();
MainActivity.adapter.notifyDataSetChanged();
mDownY = mLastEventY;
final int switchViewStartTop = switchView.getTop();
mobileView.setVisibility(View.VISIBLE);
switchView.setVisibility(View.INVISIBLE);
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<String> arrayList, int indexOne,
int indexTwo) {
Log.v("index one", indexOne + "");
Log.v("index two", indexTwo + "");
Log.v("temp", arrayList.get(indexOne));
String 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));
}
};
private void handleMobileCellScroll() {
mIsMobileScrolling = handleMobileCellScroll(mHoverCellCurrentBounds);
}
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;
}
private AbsListView.OnScrollListener mScrollListener = new AbsListView.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();
}
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();
}
}
}
};
}
LazyAdapter.java:
package com.listviewdragginganimation;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class LazyAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<String> data=new ArrayList<String>();
private static LayoutInflater inflater=null;
public ImageLoader imageLoader;
public LazyAdapter(MainActivity a, ArrayList<String> mCheeseList) {
// TODO Auto-generated constructor stub
activity = a;
data=mCheeseList;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader=new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.item, null);
TextView text=(TextView)vi.findViewById(R.id.text);;
ImageView image=(ImageView)vi.findViewById(R.id.image);
text.setText("item "+position);
imageLoader.DisplayImage(data.get(position), image);
return vi;
}
}
MainActivity.java:
package com.listviewdragginganimation;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
public class MainActivity extends Activity {
ListView list;
static LazyAdapter adapter;
static ArrayList<String>mCheeseList = new ArrayList<String>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
for (int i = 0; i < mStrings.length; ++i) {
mCheeseList.add(mStrings[i]);
}
list=(ListView)findViewById(R.id.list);
adapter=new LazyAdapter(this, mCheeseList);
list.setAdapter(adapter);
Button b=(Button)findViewById(R.id.button1);
b.setOnClickListener(listener);
}
#Override
public void onDestroy()
{
list.setAdapter(null);
super.onDestroy();
}
public OnClickListener listener=new OnClickListener(){
#Override
public void onClick(View arg0) {
adapter.imageLoader.clearCache();
adapter.notifyDataSetChanged();
}
};
private String[] mStrings={
"http://a3.twimg.com/profile_images/670625317/aam-logo-v3-twitter.png",
"http://a3.twimg.com/profile_images/740897825/AndroidCast-350_normal.png",
"http://a3.twimg.com/profile_images/121630227/Droid_normal.jpg",
"http://a1.twimg.com/profile_images/957149154/twitterhalf_normal.jpg",
"http://a1.twimg.com/profile_images/97470808/icon_normal.png",
"http://a3.twimg.com/profile_images/511790713/AG.png",
"http://a3.twimg.com/profile_images/956404323/androinica-avatar_normal.png",
"http://a1.twimg.com/profile_images/909231146/Android_Biz_Man_normal.png",
"http://a3.twimg.com/profile_images/72774055/AndroidHomme-LOGO_normal.jpg",
"http://a1.twimg.com/profile_images/349012784/android_logo_small_normal.jpg",
"http://a1.twimg.com/profile_images/841338368/ea-twitter-icon.png",
"http://a3.twimg.com/profile_images/64827025/android-wallpaper6_2560x160_normal.png",
"http://a3.twimg.com/profile_images/77641093/AndroidPlanet_normal.png",
};
}
I found this particular code https://github.com/bauerca/drag-sort-listview in this url and in it I was able to add images also...
I'm also trying to make a custom layout. Added an image (from a 'drawable' folder) to 'layout/text_view.xml' (inserted in a LinearLayout). Changed StableArrayAdapter to extend BaseAdapter and rewrote getView (I think you can also make this with ArrayAdapter like https://stackoverflow.com/a/30270370/2914140). Then applied some changes for Lollipop from ListViewDraggingAnimation broken on Android 5 Lollipop and https://www.youtube.com/all_comments?v=_BZIvjMgH-Q. At least, static images are dragged along with text. When I change an ImageView to a WebVew, there are many errors and bugs.
I have used lazy loading to download the images and thus populate in horizontal list view. But scrolling is not smooth, specially when scrolling from right to left end. These are my codes:
homepg.xml
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="none" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/Horizlistlatestnews"
android:layout_width="match_parent"
android:layout_height="105dp"
android:orientation="horizontal"
android:layout_below="#+id/Titlelatestnews"
>
<com.xxx.xxx.HorizontalView
android:id="#+id/horizontallistln"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="2dp"
android:scrollbars="none"
>
</com.xxx.xxx.HorizontalView>
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:id="#+id/Boxoffice"
android:layout_width="match_parent"
android:layout_height="145dp"
android:background="#drawable/bggray" >
<RelativeLayout
android:id="#+id/Titleboxofc"
android:layout_width="match_parent"
android:layout_height="30dp"
>
<TextView
android:id="#+id/textViewboxofc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BOX OFFICE"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:layout_alignParentLeft="true"
android:layout_marginLeft="5dp"
android:layout_centerVertical="true" />
<ProgressBar
android:id="#+id/progressBarboxofc"
android:layout_width="15dp"
android:layout_height="15dp"
android:visibility="gone"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:layout_centerVertical="true"
/>
</RelativeLayout>
<RelativeLayout
android:id="#+id/Horizlistboxofc"
android:layout_width="match_parent"
android:layout_height="105dp"
android:orientation="horizontal"
android:layout_below="#+id/Titleboxofc"
>
<com.xxx.xxx.HorizontalView
android:id="#+id/horizontallistbo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="2dp"
android:scrollbars="none"
>
</com.xxx.xxx.HorizontalView>
</RelativeLayout>
</LinearLayout>
</ScrollView>
HorizontalView.java
package com.xxx.xxx;
import java.util.LinkedList;
import java.util.Queue;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.Scroller;
public class HorizontalView extends AdapterView<Adapter> {
public boolean mAlwaysOverrideTouch = true;
protected ListAdapter mAdapter;
private int mLeftViewIndex = -1;
private int mRightViewIndex = 0;
protected int mCurrentX;
protected int mNextX;
private int mMaxX = Integer.MAX_VALUE;
private int mDisplayOffset = 0;
protected Scroller mScroller;
private GestureDetector mGesture;
private Queue mRemovedViewQueue = new LinkedList();
private OnItemSelectedListener mOnItemSelected;
private OnItemClickListener mOnItemClicked;
private OnItemLongClickListener mOnItemLongClicked;
private boolean mDataChanged = false;
public HorizontalView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private synchronized void initView() {
mLeftViewIndex = -1;
mRightViewIndex = 0;
mDisplayOffset = 0;
mCurrentX = 0;
mNextX = 0;
mMaxX = Integer.MAX_VALUE;
mScroller = new Scroller(getContext());
mGesture = new GestureDetector(getContext(), mOnGesture);
}
#Override
public void setOnItemSelectedListener(
AdapterView.OnItemSelectedListener listener) {
mOnItemSelected = listener;
}
#Override
public void setOnItemClickListener(AdapterView.OnItemClickListener listener) {
mOnItemClicked = listener;
}
#Override
public void setOnItemLongClickListener(
AdapterView.OnItemLongClickListener listener) {
mOnItemLongClicked = listener;
}
private DataSetObserver mDataObserver = new DataSetObserver() {
#Override
public void onChanged() {
synchronized (HorizontalView.this) {
mDataChanged = true;
}
invalidate();
requestLayout();
}
#Override
public void onInvalidated() {
reset();
invalidate();
requestLayout();
}
};
#Override
public Adapter getAdapter() {
return mAdapter;
}
#Override
public View getSelectedView() {
return null;
}
#Override
public void setAdapter(Adapter adapter) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mDataObserver);
}
mAdapter = (ListAdapter) adapter;
mAdapter.registerDataSetObserver(mDataObserver);
reset();
}
private synchronized void reset() {
initView();
removeAllViewsInLayout();
requestLayout();
}
#Override
public void setSelection(int position) {
}
private void addAndMeasureChild(final View child, int viewPos) {
LayoutParams params = child.getLayoutParams();
if (params == null) {
params = new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
}
addViewInLayout(child, viewPos, params, true);
child.measure(
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
}
#Override
protected synchronized void onLayout(boolean changed, int left, int top,
int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mAdapter == null) {
return;
}
if (mDataChanged) {
int oldCurrentX = mCurrentX;
initView();
removeAllViewsInLayout();
mNextX = oldCurrentX;
mDataChanged = false;
}
if (mScroller.computeScrollOffset()) {
int scrollx = mScroller.getCurrX();
mNextX = scrollx;
}
if (mNextX <= 0) {
mNextX = 0;
mScroller.forceFinished(true);
}
if (mNextX >= mMaxX) {
mNextX = mMaxX;
mScroller.forceFinished(true);
}
int dx = mCurrentX - mNextX;
// removeNonVisibleItems(dx);
fillList(dx);
positionItems(dx);
mCurrentX = mNextX;
if (!mScroller.isFinished()) {
post(new Runnable() {
#Override
public void run() {
requestLayout();
}
});
}
}
private void fillList(final int dx) {
int edge = 0;
View child = getChildAt(getChildCount() - 1);
if (child != null) {
edge = child.getRight();
}
fillListRight(edge, dx);
edge = 0;
child = getChildAt(0);
if (child != null) {
edge = child.getLeft();
}
fillListLeft(edge, dx);
}
private void fillListRight(int rightEdge, final int dx) {
while (rightEdge + dx < getWidth()
&& mRightViewIndex < mAdapter.getCount()) {
View child = mAdapter.getView(mRightViewIndex,
(View) mRemovedViewQueue.poll(), this);
addAndMeasureChild(child, -1);
rightEdge += child.getMeasuredWidth();
if (mRightViewIndex == mAdapter.getCount() - 1) {
mMaxX = mCurrentX + rightEdge - getWidth();
}
if (mMaxX < 0) {
mMaxX = 0;
}
mRightViewIndex++;
}
}
private void fillListLeft(int leftEdge, final int dx) {
while (leftEdge + dx > 0 && mLeftViewIndex >= 0) {
View child = mAdapter.getView(mLeftViewIndex,
(View) mRemovedViewQueue.poll(), this);
addAndMeasureChild(child, 0);
leftEdge -= child.getMeasuredWidth();
mLeftViewIndex--;
mDisplayOffset -= child.getMeasuredWidth();
}
}
private void positionItems(final int dx) {
if (getChildCount() > 0) {
mDisplayOffset += dx;
int left = mDisplayOffset;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
int childWidth = child.getMeasuredWidth();
child.layout(left, 0, left + childWidth,
child.getMeasuredHeight());
left += childWidth;
}
}
}
public synchronized void scrollTo(int x) {
mScroller.startScroll(mNextX, 0, x - mNextX, 0);
requestLayout();
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean handled = super.dispatchTouchEvent(ev);
handled |= mGesture.onTouchEvent(ev);
return handled;
}
protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
synchronized (HorizontalView.this) {
mScroller.fling(mNextX, 0, (int) -velocityX, 0, 0, mMaxX, 0, 0);
}
requestLayout();
return true;
}
protected boolean onDown(MotionEvent e) {
mScroller.forceFinished(true);
return true;
}
private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() {
public boolean onDown(MotionEvent e) {
return HorizontalView.this.onDown(e);
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return HorizontalView.this.onFling(e1, e2, velocityX, velocityY);
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
synchronized (HorizontalView.this) {
mNextX += (int) distanceX;
}
requestLayout();
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (isEventWithinView(e, child)) {
if (mOnItemClicked != null) {
mOnItemClicked.onItemClick(HorizontalView.this, child,
mLeftViewIndex + 1 + i,
mAdapter.getItemId(mLeftViewIndex + 1 + i));
}
if (mOnItemSelected != null) {
mOnItemSelected.onItemSelected(HorizontalView.this,
child, mLeftViewIndex + 1 + i,
mAdapter.getItemId(mLeftViewIndex + 1 + i));
}
break;
}
}
return true;
}
#Override
public void onLongPress(MotionEvent e) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (isEventWithinView(e, child)) {
if (mOnItemLongClicked != null) {
mOnItemLongClicked.onItemLongClick(HorizontalView.this,
child, mLeftViewIndex + 1 + i,
mAdapter.getItemId(mLeftViewIndex + 1 + i));
}
break;
}
}
}
private boolean isEventWithinView(MotionEvent e, View child) {
Rect viewRect = new Rect();
int[] childPosition = new int[2];
child.getLocationOnScreen(childPosition);
int left = childPosition[0];
int right = left + child.getWidth();
int top = childPosition[1];
int bottom = top + child.getHeight();
viewRect.set(left, top, right, bottom);
return viewRect.contains((int) e.getRawX(), (int) e.getRawY());
}
};
}
HorizontalImageAdapter.java
package com.xxx.xxx;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ImageView.ScaleType;
public class HorizontalImageAdapter extends ArrayAdapter<RSSItem> {
//private Context context;
private List<RSSItem> objectsln = new ArrayList<RSSItem>();
int ResourceId;
private Activity activity;
public ImageManager imageManager1;
private static ViewHolder holder;
public HorizontalImageAdapter(Activity a, int textViewResourceId, List<RSSItem> objectsln) {
super(a, textViewResourceId, objectsln);
System.out.println("LISTVIEW Constructor Called");
activity = a;
this.objectsln = objectsln;
this.ResourceId = textViewResourceId;
imageManager1 = new ImageManager(activity.getApplicationContext());
}
#Override
public int getCount() {
return this.objectsln.size();
}
#Override
public RSSItem getItem(int position) {
return this.objectsln.get(position);
}
#Override
public long getItemId(int position) {
System.out.println("LISTVIEW POSITION Called: "+position);
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
holder = new ViewHolder();
LayoutInflater infleter = (LayoutInflater) this.getContext().getSystemService(Context.
LAYOUT_INFLATER_SERVICE);
convertView = infleter.inflate(ResourceId, parent, false);
holder = new ViewHolder();
holder.imageViewln = (ImageView) convertView.findViewById(R.id.imageViewhlist);
holder.textviewln=(TextView)convertView.findViewById(R.id.textViewhlist);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
RSSItem dataln = null ;
//get the item
if(objectsln.size() !=0){
dataln = getItem(position);
}else{
Log.i("test TAG", "Size zero found");
}
if (dataln != null) {
holder.textviewln.setText(dataln.title); // For taking the title from
// Web Services and set into text view
System.out.println("TITLE LATEST NEWS - "+position+": "+dataln.title);
holder.imageViewln.setScaleType(ScaleType.FIT_XY);
holder.imageViewln.setTag(dataln.imageurl);
imageManager1.displayImage(dataln.imageurl, activity,
holder.imageViewln);
}
return convertView;
}
private static class ViewHolder {
ImageView imageViewln;
TextView textviewln;
}
}
How can a drag and drop functionality be implemented in Android GridView. Can anyone please provide the best link for the same?
see PagedDragDropGrid
Above example has implemented a paged grid with drag'n'drop movable items using ViewGroup.
Note# It supports Android 2.2 (API 8) and above.
This is finest example i ever seen in android drag and drop android 2.2. And which version you have used?
You can find the google's documentation on drag and drop here and a third parties example here.
What you're going to want to do is set every view in your gridView to be clickable and set the onTouchListener. In your onTouch method you would then handle the appropriate actions for ACTION_DOWN (user pressed down on screen), ACTION_MOVE (user moves finger around ont he screen) and ACTION_UP (user lifts finger from the screen).
Try another approach by using WindowManager :
package com.example.cooldraganddrop;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ImageView;
public class CoolDragAndDropGridView extends SpanVariableGridView implements `View.OnTouchListener {`
private static final int ITEM_HOVER_DELAY = 450;
private int mDragPointX;
private int mDragPointY;
private int mDragOffsetX;
private int mDragOffsetY;
private int mDragPosition = AdapterView.INVALID_POSITION;
private int mDropPosition = AdapterView.INVALID_POSITION;
private int mCurrentPosition = AdapterView.INVALID_POSITION;
private Runnable mDelayedOnDragRunnable = null;
ScrollingStrategy mScrollingStrategy = null;
WindowManager mWindowManager = null;
WindowManager.LayoutParams mWindowParams = null;
private ImageView mDragImageView = null;
private boolean mDragAndDropStarted = false;
private DragAndDropListener mDragAndDropListener = null;
private OnTrackTouchEventsListener mOnTrackTouchEventsListener = null;
public static interface OnTrackTouchEventsListener {
void trackTouchEvents(final MotionEvent motionEvent);
};
public static interface DragAndDropListener {
void onDragItem(int from);
void onDraggingItem(int from, int to);
void onDropItem(int from, int to);
boolean isDragAndDropEnabled(int position);
}
public CoolDragAndDropGridView(Context context) {
super(context);
initialize();
}
public CoolDragAndDropGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize();
}
public CoolDragAndDropGridView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
private void initialize() {
setOnTouchListener(this);
setChildrenDrawingOrderEnabled(true);
}
public void startDragAndDrop() {
mDragAndDropStarted = true;
}
public void setDragAndDropListener(DragAndDropListener dragAndDropListener) {
mDragAndDropListener = dragAndDropListener;
}
private void destroyDragImageView() {
if (mDragImageView != null) {
mWindowManager.removeView(mDragImageView);
BitmapDrawable bitmapDrawable = (BitmapDrawable) mDragImageView.getDrawable();
if (bitmapDrawable != null) {
final Bitmap bitmap = bitmapDrawable.getBitmap();
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
}
mDragImageView.setImageDrawable(null);
mDragImageView = null;
}
}
private ImageView createDragImageView(final View v, final int x, final int y) {
v.destroyDrawingCache();
v.setDrawingCacheEnabled(true);
Bitmap bm = Bitmap.createBitmap(v.getDrawingCache());
mDragPointX = x - v.getLeft();
mDragPointY = y - v.getTop();
mWindowParams = new WindowManager.LayoutParams();
mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
mWindowParams.x = x - mDragPointX + mDragOffsetX;
mWindowParams.y = y - mDragPointY + mDragOffsetY;
mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
mWindowParams.format = PixelFormat.TRANSLUCENT;
mWindowParams.alpha = 0.7f;
mWindowParams.windowAnimations = 0;
ImageView iv = new ImageView(getContext());
iv.setBackgroundColor(Color.parseColor("#ff555555"));
iv.setImageBitmap(bm);
mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);// "window"
mWindowManager.addView(iv, mWindowParams);
return iv;
}
private void startDrag(final int x, final int y) {
final View v = getChildAt(mDragPosition);
destroyDragImageView();
mDragImageView = createDragImageView(v, x, y);
v.setVisibility(View.INVISIBLE);
if (mDragAndDropListener != null) {
mDragAndDropListener.onDragItem(mDragPosition);
}
}
#Override
protected int getChildDrawingOrder(int childCount, int i) {
if (mCurrentPosition == -1)
return i;
else if (i == childCount - 1)
return mCurrentPosition;
else if (i >= mCurrentPosition)
return i + 1;
return i;
}
private void onDrop() {
destroyDragImageView();
removeCallbacks(mDelayedOnDragRunnable);
View v = getChildAt(mDropPosition);
v.setVisibility(View.VISIBLE);
v.clearAnimation();
if (mDragAndDropListener != null && mDropPosition != AdapterView.INVALID_POSITION) {
mDragAndDropListener.onDropItem(mDragPosition, mDropPosition);
}
mDragPosition = mDropPosition = mCurrentPosition = AdapterView.INVALID_POSITION;
mDragAndDropStarted = false;
}
public void setScrollingStrategy(ScrollingStrategy scrollingStrategy) {
mScrollingStrategy = scrollingStrategy;
}
private void onDrag(final int x, final int y) {
if (mScrollingStrategy != null && mScrollingStrategy.performScrolling(x, y, this)) {
removeCallbacks(mDelayedOnDragRunnable);
return;
}
final int tempDropPosition = pointToPosition(mCurrentPosition, x, y);
if (mDragAndDropListener != null && mDropPosition != tempDropPosition && tempDropPosition != AdapterView.INVALID_POSITION) {
removeCallbacks(mDelayedOnDragRunnable);
if (mDragAndDropListener.isDragAndDropEnabled(tempDropPosition)) {
mDropPosition = tempDropPosition;
mDelayedOnDragRunnable = new Runnable() {
#Override
public void run() {
mDragAndDropListener.onDraggingItem(mCurrentPosition, tempDropPosition);
performDragAndDropSwapping(mCurrentPosition, tempDropPosition);
final int nextDropPosition = pointToPosition(tempDropPosition, x, y);
if (nextDropPosition == AdapterView.INVALID_POSITION) {
mCurrentPosition = mDropPosition = tempDropPosition;
}
}
};
postDelayed(mDelayedOnDragRunnable, ITEM_HOVER_DELAY);
} else {
mDropPosition = mDragPosition;
}
}
if (mDragImageView != null) {
mWindowParams.x = x - mDragPointX + mDragOffsetX;
mWindowParams.y = y - mDragPointY + mDragOffsetY;
mWindowManager.updateViewLayout(mDragImageView, mWindowParams);
}
}
public void setOnTrackTouchEventListener(OnTrackTouchEventsListener onTrackTouchEventsListener) {
mOnTrackTouchEventsListener = onTrackTouchEventsListener;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mOnTrackTouchEventsListener != null) {
mOnTrackTouchEventsListener.trackTouchEvents(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
if (mDragAndDropListener != null && mDragAndDropStarted) {
mDragAndDropStarted = false;
getParent().requestDisallowInterceptTouchEvent(true);
return launchDragAndDrop(event);
}
break;
default:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mDragAndDropStarted = false;
getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return super.onInterceptTouchEvent(event);
}
private boolean launchDragAndDrop(final MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
mCurrentPosition = mDragPosition = mDropPosition = pointToPosition(mDragPosition, x, y);
if (mDragPosition != AdapterView.INVALID_POSITION && mDragAndDropListener.isDragAndDropEnabled(mDragPosition)) {
mDragOffsetX = (int) (event.getRawX() - x);
mDragOffsetY = (int) (event.getRawY() - y);
startDrag(x, y);
return true;
}
return false;
}
#Override
public boolean onTouch(View view, MotionEvent event) {
if (mDragPosition != AdapterView.INVALID_POSITION && mDragImageView != null) {
final int x = (int) event.getX();
final int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
mDragOffsetX = (int) (event.getRawX() - x);
mDragOffsetY = (int) (event.getRawY() - y);
onDrag(x, y);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
onDrop();
resetLongClickTransition();
getParent().requestDisallowInterceptTouchEvent(false);
return false;
default:
}
return true;
}
return false;
}
}
Sample using this approach of a drag and drop is here