自定义gridview

import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.os.Handler;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.AdapterView.OnItemClickListener; import java.util.ArrayList;
import java.util.Collections; /**
* Created by Administrator on 2017/2/27.
*/
public class DraggableGridView extends ViewGroup implements View.OnTouchListener, View.OnClickListener, View.OnLongClickListener {
//layout vars
public static float childRatio = .9f;
protected int colCount, childSize, padding, dpi, scroll = 0;
protected float lastDelta = 0;
protected Handler handler = new Handler();
//dragging vars
protected int dragged = -1, lastX = -1, lastY = -1, lastTarget = -1;
protected boolean enabled = true, touching = false;
//anim vars
public static int animT = 150;
protected ArrayList<Integer> newPositions = new ArrayList<Integer>();
//listeners
protected OnRearrangeListener onRearrangeListener;
protected OnClickListener secondaryOnClickListener;
private OnItemClickListener onItemClickListener; //CONSTRUCTOR AND HELPERS
public DraggableGridView(Context context, AttributeSet attrs) {
super(context, attrs);
setListeners();
handler.removeCallbacks(updateTask);
handler.postAtTime(updateTask, SystemClock.uptimeMillis() + 500);
setChildrenDrawingOrderEnabled(true); DisplayMetrics metrics = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metrics);
dpi = metrics.densityDpi;
} protected void setListeners() {
setOnTouchListener(this);
super.setOnClickListener(this);
setOnLongClickListener(this);
} @Override
public void setOnClickListener(OnClickListener l) {
secondaryOnClickListener = l;
} protected Runnable updateTask = new Runnable() {
public void run() {
if (dragged != -1) {
if (lastY < padding * 3 && scroll > 0)
scroll -= 20;
else if (lastY > getBottom() - getTop() - (padding * 3) && scroll < getMaxScroll())
scroll += 20;
} else if (lastDelta != 0 && !touching) {
scroll += lastDelta;
lastDelta *= .9;
if (Math.abs(lastDelta) < .25)
lastDelta = 0;
}
clampScroll();
onLayout(true, getLeft(), getTop(), getRight(), getBottom()); handler.postDelayed(this, 25);
}
}; //OVERRIDES
@Override
public void addView(View child) {
super.addView(child);
newPositions.add(-1);
} ; @Override
public void removeViewAt(int index) {
super.removeViewAt(index);
newPositions.remove(index);
} ; //LAYOUT
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//compute width of view, in dp
float w = (r - l) / (dpi / 160f); //determine number of columns, at least 2
colCount = 2;
int sub = 240;
w -= 280;
while (w > 0) {
colCount++;
w -= sub;
sub += 40;
} //determine childSize and padding, in px
childSize = (r - l) / colCount;
childSize = Math.round(childSize * childRatio);
padding = ((r - l) - (childSize * colCount)) / (colCount + 1); for (int i = 0; i < getChildCount(); i++)
if (i != dragged) {
Point xy = getCoorFromIndex(i);
getChildAt(i).layout(xy.x, xy.y, xy.x + childSize, xy.y + childSize);
}
} @Override
protected int getChildDrawingOrder(int childCount, int i) {
if (dragged == -1)
return i;
else if (i == childCount - 1)
return dragged;
else if (i >= dragged)
return i + 1;
return i;
} public int getIndexFromCoor(int x, int y) {
int col = getColOrRowFromCoor(x), row = getColOrRowFromCoor(y + scroll);
if (col == -1 || row == -1) //touch is between columns or rows
return -1;
int index = row * colCount + col;
if (index >= getChildCount())
return -1;
return index;
} protected int getColOrRowFromCoor(int coor) {
coor -= padding;
for (int i = 0; coor > 0; i++) {
if (coor < childSize)
return i;
coor -= (childSize + padding);
}
return -1;
} protected int getTargetFromCoor(int x, int y) {
if (getColOrRowFromCoor(y + scroll) == -1) //touch is between rows
return -1;
//if (getIndexFromCoor(x, y) != -1) //touch on top of another visual
//return -1; int leftPos = getIndexFromCoor(x - (childSize / 4), y);
int rightPos = getIndexFromCoor(x + (childSize / 4), y);
if (leftPos == -1 && rightPos == -1) //touch is in the middle of nowhere
return -1;
if (leftPos == rightPos) //touch is in the middle of a visual
return -1; int target = -1;
if (rightPos > -1)
target = rightPos;
else if (leftPos > -1)
target = leftPos + 1;
if (dragged < target)
return target - 1; //Toast.makeText(getContext(), "Target: " + target + ".", Toast.LENGTH_SHORT).show();
return target;
} protected Point getCoorFromIndex(int index) {
int col = index % colCount;
int row = index / colCount;
return new Point(padding + (childSize + padding) * col,
padding + (childSize + padding) * row - scroll);
} public int getIndexOf(View child) {
for (int i = 0; i < getChildCount(); i++)
if (getChildAt(i) == child)
return i;
return -1;
} //EVENT HANDLERS
public void onClick(View view) {
if (enabled) {
if (secondaryOnClickListener != null)
secondaryOnClickListener.onClick(view);
if (onItemClickListener != null && getLastIndex() != -1)
onItemClickListener.onItemClick(null, getChildAt(getLastIndex()), getLastIndex(), getLastIndex() / colCount);
}
} public boolean onLongClick(View view) {
if (!enabled)
return false;
int index = getLastIndex();
if (index != -1) {
dragged = index;
animateDragged();
return true;
}
return false;
} public boolean onTouch(View view, MotionEvent event) {
int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
enabled = true;
lastX = (int) event.getX();
lastY = (int) event.getY();
touching = true;
break;
case MotionEvent.ACTION_MOVE:
int delta = lastY - (int) event.getY();
if (dragged != -1) {
//change draw location of dragged visual
int x = (int) event.getX(), y = (int) event.getY();
int l = x - (3 * childSize / 4), t = y - (3 * childSize / 4);
getChildAt(dragged).layout(l, t, l + (childSize * 3 / 2), t + (childSize * 3 / 2)); //check for new target hover
int target = getTargetFromCoor(x, y);
if (lastTarget != target) {
if (target != -1) {
animateGap(target);
lastTarget = target;
}
}
} else {
scroll += delta;
clampScroll();
if (Math.abs(delta) > 2)
enabled = false;
onLayout(true, getLeft(), getTop(), getRight(), getBottom());
}
lastX = (int) event.getX();
lastY = (int) event.getY();
lastDelta = delta;
break;
case MotionEvent.ACTION_UP:
if (dragged != -1) {
View v = getChildAt(dragged);
if (lastTarget != -1)
reorderChildren();
else {
Point xy = getCoorFromIndex(dragged);
v.layout(xy.x, xy.y, xy.x + childSize, xy.y + childSize);
}
v.clearAnimation();
if (v instanceof ImageView)
((ImageView) v).setAlpha(255);
lastTarget = -1;
dragged = -1;
}
touching = false;
break;
}
if (dragged != -1)
return true;
return false;
} //EVENT HELPERS
protected void animateDragged() {
View v = getChildAt(dragged);
int x = getCoorFromIndex(dragged).x + childSize / 2, y = getCoorFromIndex(dragged).y + childSize / 2;
int l = x - (3 * childSize / 4), t = y - (3 * childSize / 4);
v.layout(l, t, l + (childSize * 3 / 2), t + (childSize * 3 / 2));
AnimationSet animSet = new AnimationSet(true);
ScaleAnimation scale = new ScaleAnimation(.667f, 1, .667f, 1, childSize * 3 / 4, childSize * 3 / 4);
scale.setDuration(animT);
AlphaAnimation alpha = new AlphaAnimation(1, .5f);
alpha.setDuration(animT); animSet.addAnimation(scale);
animSet.addAnimation(alpha);
animSet.setFillEnabled(true);
animSet.setFillAfter(true); v.clearAnimation();
v.startAnimation(animSet);
} protected void animateGap(int target) {
for (int i = 0; i < getChildCount(); i++) {
View v = getChildAt(i);
if (i == dragged)
continue;
int newPos = i;
if (dragged < target && i >= dragged + 1 && i <= target)
newPos--;
else if (target < dragged && i >= target && i < dragged)
newPos++; //animate
int oldPos = i;
if (newPositions.get(i) != -1)
oldPos = newPositions.get(i);
if (oldPos == newPos)
continue; Point oldXY = getCoorFromIndex(oldPos);
Point newXY = getCoorFromIndex(newPos);
Point oldOffset = new Point(oldXY.x - v.getLeft(), oldXY.y - v.getTop());
Point newOffset = new Point(newXY.x - v.getLeft(), newXY.y - v.getTop()); TranslateAnimation translate = new TranslateAnimation(Animation.ABSOLUTE, oldOffset.x,
Animation.ABSOLUTE, newOffset.x,
Animation.ABSOLUTE, oldOffset.y,
Animation.ABSOLUTE, newOffset.y);
translate.setDuration(animT);
translate.setFillEnabled(true);
translate.setFillAfter(true);
v.clearAnimation();
v.startAnimation(translate); newPositions.set(i, newPos);
}
} protected void reorderChildren() {
//FIGURE OUT HOW TO REORDER CHILDREN WITHOUT REMOVING THEM ALL AND RECONSTRUCTING THE LIST!!!
if (onRearrangeListener != null)
onRearrangeListener.onRearrange(dragged, lastTarget);
ArrayList<View> children = new ArrayList<View>();
for (int i = 0; i < getChildCount(); i++) {
getChildAt(i).clearAnimation();
children.add(getChildAt(i));
}
removeAllViews();
while (dragged != lastTarget)
if (lastTarget == children.size()) // dragged and dropped to the right of the last element
{
children.add(children.remove(dragged));
dragged = lastTarget;
} else if (dragged < lastTarget) // shift to the right
{
Collections.swap(children, dragged, dragged + 1);
dragged++;
} else if (dragged > lastTarget) // shift to the left
{
Collections.swap(children, dragged, dragged - 1);
dragged--;
}
for (int i = 0; i < children.size(); i++) {
newPositions.set(i, -1);
addView(children.get(i));
}
onLayout(true, getLeft(), getTop(), getRight(), getBottom());
} public void scrollToTop() {
scroll = 0;
} public void scrollToBottom() {
scroll = Integer.MAX_VALUE;
clampScroll();
} protected void clampScroll() {
int stretch = 3, overreach = getHeight() / 2;
int max = getMaxScroll();
max = Math.max(max, 0); if (scroll < -overreach) {
scroll = -overreach;
lastDelta = 0;
} else if (scroll > max + overreach) {
scroll = max + overreach;
lastDelta = 0;
} else if (scroll < 0) {
if (scroll >= -stretch)
scroll = 0;
else if (!touching)
scroll -= scroll / stretch;
} else if (scroll > max) {
if (scroll <= max + stretch)
scroll = max;
else if (!touching)
scroll += (max - scroll) / stretch;
}
} protected int getMaxScroll() {
int rowCount = (int) Math.ceil((double) getChildCount() / colCount), max = rowCount * childSize + (rowCount + 1) * padding - getHeight();
return max;
} public int getLastIndex() {
return getIndexFromCoor(lastX, lastY);
} //OTHER METHODS
public void setOnRearrangeListener(OnRearrangeListener l) {
this.onRearrangeListener = l;
} public void setOnItemClickListener(OnItemClickListener l) {
this.onItemClickListener = l;
}
}

使用:

import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.TextView; public class MainActivity extends AppCompatActivity { private DraggableGridView vgv; @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vgv = (DraggableGridView) findViewById(R.id.vgv);
for (int i = 0; i < 10; i++) {
TextView textView = new TextView(this);
textView.setText(i + "");
textView.setBackground(getResources().getDrawable(R.drawable.tv_bg));
textView.setGravity(Gravity.CENTER);
vgv.addView(textView);
} vgv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
vgv.removeViewAt(position);
}
});
}
}

可随意交换位置的gridview的更多相关文章

  1. Android 高级UI设计笔记02:可以拖动交换item位置的GridView(转载)

    如果大家不知道GridView基本使用,可以先参见:Android(java)学习笔记154:使用GridView以及重写BaseAdapter 1. 首先我们明白GridView拖拽的思路: ()根 ...

  2. Android DynamicGrid:拖曳交换位置

     Android DynamicGrid:拖曳交换位置 Android DynamicGrid是一个第三方开源项目,DynamicGrid在github上的项目主页是:https://github ...

  3. 用C语言把双向链表中的两个结点交换位置,考虑各种边界问题。

    用C语言把双向链表中的两个结点交换位置,考虑各种边界问题. [参考] http://blog.csdn.net/silangquan/article/details/18051675

  4. ListView实现Item上下拖动交换位置 并且实现下拉刷新 上拉加载更多

    ListView实现Item上下拖动交换位置  并且实现下拉刷新  上拉加载更多 package com.example.ListViewDragItem; import android.app.Ac ...

  5. js 实现数组元素交换位置

    /** * 数组元素交换位置 * @param {array} arr 数组 * @param {number} index1 添加项目的位置 * @param {number} index2 删除项 ...

  6. C语言 选择排序算法原理和实现 从数组中 找出最小的元素然后交换位置

    #include <stdio.h> int main(void) { /* 选择排序算法 原理:从数组中 找出最小的元素然后交换位置: */ int a[10] = {9,5,10,7, ...

  7. C语言:对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中。-在数组中找出最小值,并与第一个元素交换位置。

    //对传入sp的字符进行统计,三组两个相连字母“ea”"ou""iu"出现的次数,并将统计结果存入ct所指的数组中. #include <stdio.h& ...

  8. Young Table(暴力,交换位置)

     Young Table Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submi ...

  9. java例题_35 找到最大值和最小值并交换位置

    1 /*35 [程序 35 最大最小交换] 2 题目:输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组. 3 */ 4 5 /*分析 6 * 1.先初始化一个数组,然后从键盘获得值 ...

随机推荐

  1. bootstrap 栅格calss

    container container-fluid row col-xs- col-sm- col-md- col-lg- col-md-offset- col-md-push- col-md-pul ...

  2. libuv移植到ios

    libuv官网只提供了os x的编译方法,没有IOS的.既然os x和ios的系统内核差不多,并且编译工具都是xcode,那我们只要重新指定cpu架构,就可以编译出ios版的了. 1.安装python ...

  3. 「七天自制PHP框架」应用:JSON生成器

    刚刚开始学做一个WebAPP,数据查询的一般套路是通过一张PHP页面读取数据库,获得列表后“嵌写”在PHP页面中,虽然写法上丑陋至极,但也有“快糙猛”出效果的成就感,如图. 后来想想,不对啊,难道以后 ...

  4. [POJ 2559]Largest Rectangle in a Histogram 题解(单调栈)

    [POJ 2559]Largest Rectangle in a Histogram Description A histogram is a polygon composed of a sequen ...

  5. eclipse运行Android项目出现“The connection to adb is down, and a severe error has occured. You must restart adb and Eclipse. ”

    重启eclipse之后仍然出现同样错误,此时可以尝试一下方法: cmd打开命令窗口: 之后重启eclipse,基本可以解决问题!

  6. 【译】第五篇 SQL Server代理理解代理错误日志

    本篇文章是SQL Server代理系列的第五篇,详细内容请参考原文. 正如这一系列的前几篇所述,SQL Server代理作业是由一系列的作业步骤组成,每个步骤由一个独立的类型去执行.在第四篇中我们看到 ...

  7. Flask 的一个小应用程序

    传说这是Flask 的最小应用程序:hello.py from flask import Flask app = Flask(__name__) @app.route('/') def hello_w ...

  8. jquery 生成二维码

    jquery的二维码生成插件qrcode,在页面中调用该插件就能生成对应的二维码 <!DOCTYPE html> <html> <head> <meta ch ...

  9. Linux 添加普通用户到 sudoers 文件

    前言 Linux 的普通用户(uid >= 500)不具有某些命令的执行权限,为了执行较高权限的命令,一般有两种方法: 第一种是使用 su - 命令切换到 root 用户去执行: 另外一种方法是 ...

  10. Transport failed: java.io.EOFException

    ActiveMQ服务端有时会报Transport failed: java.io.EOFException这样的错误,这是由客户端丢失连接并反复尝试连接导致的,不是什么大问题,有时网络波动就会产生这种 ...