发现之前的东西些复杂
Android中GridView中onTouch监听(1)每个item进行点击缩放动画的制作以及点击事件的监听
Android中GridView中onTouch监听(2)自己写的Scroll滑动判断
现在把它写成一个自定义控件,方便扩展。
效果如下:
主要就是在自定义控件的onTouchEvent中写自己的动画效果
代码如下:
package com.example.mygridviewdemo;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.GridView;
/**
* 实现点击 item做缩放动画
*
* @author leafact
*
*/
public class TouchableGridView extends GridView {
private Context context;
// action down按下动画
private static Animation downAnimation;
// action up动画
private static Animation upAnimation;
// 前一个元素
private static int tempChildViewId = -1;
private static int downChildViewId = -1;
private static int upChildViewId = -2;
private static boolean isLastView = true;
private static final int numColumns = 3;
public TouchableGridView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
showAnimation(ev);
// 扩展重写
return super.onTouchEvent(ev);
}
private void showAnimation(MotionEvent event) {
// 判断是不是GridView的v
if (!(this instanceof GridView))
return;
GridView parent = ((GridView) this);
int count = parent.getChildCount();
// 没有元素不做动画
if (count == 0)
return;
// 获得每个元素的大小。这里每个gridView的元素都是相同大小的,取第一个为例。
int childWidth = parent.getChildAt(0).getWidth() + 10;
int childHeight = parent.getChildAt(0).getHeight() + 2;
Log.d("count", "==" + count);
// 进行事件监听
switch (event.getAction()) {
// 按下的时候,获得当前元素的id,由于我一行是numColumns个,所以我的y方向上就必须乘以numColumns
// 例如我按下的是第numColumns个(从第0个开始,第三个为第二行第一列),那么第三个=点击x的大小/子元素的x的大小+(点击y的大小/子元素的y的大小)*numColumns=0+numColumns=numColumns、
case MotionEvent.ACTION_DOWN: {
// 重置
tempChildViewId = -1;
downChildViewId = -1;
upChildViewId = -2;
isLastView = true;
// 三目运算符
int currentChildViewId = ((int) event.getX() / childWidth + ((int) event
.getY() + parent.getScrollY()) / childHeight * numColumns) < count ? ((int) event
.getX() / childWidth + ((int) event.getY() + parent
.getScrollY()) / childHeight * numColumns)
: -1;
// 开始按没按在存在的元素中的时候这个动画不做
if (currentChildViewId == -1)
return;
// 进行缩小动画
downAnimation = AnimationUtils.loadAnimation(context,
R.anim.backgroundanimdown);
parent.getChildAt(currentChildViewId).startAnimation(downAnimation);
tempChildViewId = currentChildViewId;
downChildViewId = currentChildViewId;
break;
}
// 通过位置判断是哪个item,做对应的动画
case MotionEvent.ACTION_MOVE: {
// 计算出当前chidView的位于gridView中的位置
int currentChildViewId = ((int) event.getX() / childWidth + ((int) event
.getY() + parent.getScrollY()) / childHeight * numColumns) < count ? ((int) event
.getX() / childWidth + ((int) event.getY() + parent
.getScrollY()) / childHeight * numColumns)
: -1;
// 当之前一个元素存在,而移动到不存在元素的区域的时候,需要立即将之前图片抬起
// 由于这个方法只让他走一次。设置了一个isLastView的boolean参数
if (tempChildViewId != -1 && currentChildViewId == -1 && isLastView) {
Log.d("movemove", "movemove");
isLastView = false;
upAnimation = AnimationUtils.loadAnimation(context,
R.anim.backgroundanimup);
parent.getChildAt(tempChildViewId).startAnimation(upAnimation);
return;
}
if (currentChildViewId == -1)
return;
// 当前元素与之前元素相同,不执行变化操作。
if (currentChildViewId != tempChildViewId) {
// 表示从不存在的元素移动到存在的元素的时候。只需要做按下操作即可
if (tempChildViewId == -1) {
downAnimation = AnimationUtils.loadAnimation(context,
R.anim.backgroundanimdown);
parent.getChildAt(currentChildViewId).startAnimation(
downAnimation);
} else {
// 表示从存在的元素移动到另外一个存在的元素的时候。只需要做按下操作即可
// 原来的动画变成弹起。之后的那个执行新的动画
upAnimation = AnimationUtils.loadAnimation(context,
R.anim.backgroundanimup);
parent.getChildAt(tempChildViewId).startAnimation(
upAnimation);
downAnimation = AnimationUtils.loadAnimation(context,
R.anim.backgroundanimdown);
parent.getChildAt(currentChildViewId).startAnimation(
downAnimation);
}
// 改变前一个元素的位置。
tempChildViewId = currentChildViewId;
}
break;
}
// 抬起,松手的时候
case MotionEvent.ACTION_UP: {
int currentChildViewId = ((int) event.getX() / childWidth + ((int) event
.getY() + parent.getScrollY()) / childHeight * numColumns) < count ? ((int) event
.getX() / childWidth + ((int) event.getY() + parent
.getScrollY()) / childHeight * numColumns)
: -1;
Log.d("currentChildViewId", currentChildViewId + "");
// 按下和抬起都在无效位置的话,do nothing
if (currentChildViewId == -1)
return;
// 其他情况下,需要收起当前的动画
upAnimation = AnimationUtils.loadAnimation(context,
R.anim.backgroundanimup);
parent.getChildAt(currentChildViewId).startAnimation(upAnimation);
upChildViewId = currentChildViewId;
}
default:
break;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
注意这里的onTouchEvent 中返回值,是调用super的方法(父类的方法),也就是扩展重写,如果返回true,拦截的话,之后的滑动以及点击事件也要自己重新写,但是这样写就不需要了。
两个动画写在anim文件夹中
按下的动画:缩小
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1"
android:fromYScale="1"
android:toXScale="0.8"
android:toYScale="0.8"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="true"
android:duration="300"
/>
离开时候的动画,放大
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.8"
android:fromYScale="0.8"
android:toXScale="1"
android:toYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="true"
android:duration="500"
/>
mainActivity里面
package com.example.mygridviewdemo;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Toast;
public class MainActivity extends Activity {
private TouchableGridView touchableGridView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
touchableGridView = (TouchableGridView) findViewById(R.id.touchableGridView);
List<String> data = new ArrayList<String>();
for (int i = 0; i < 30; i++) {
data.add("" + i);
}
touchableGridView.setAdapter(new TypeGridViewAdapter(this, data));
touchableGridView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(MainActivity.this, "onItemClick",
Toast.LENGTH_SHORT).show();
}
});
}
}
xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<!-- numColumns为列数-->
<com.example.mygridviewdemo.TouchableGridView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="3"
android:horizontalSpacing="2dp"
android:verticalSpacing="2dp"
android:id="@+id/touchableGridView"
/>
</RelativeLayout>
当然还需要自定义一个适配器,里面设置每个item的背景颜色和文本内容,以及对于item的xml布局,这里就累赘了。
===================
之后的学习发现原来要获取选择的item的id,其实安卓提供了方法
/**
* Maps a point to a position in the list.
*
* @param x X in local coordinate
* @param y Y in local coordinate
* @return The position of the item which contains the specified point, or
* {@link #INVALID_POSITION} if the point does not intersect an item.
*/
public int pointToPosition(int x, int y) {
Rect frame = mTouchFrame;
if (frame == null) {
mTouchFrame = new Rect();
frame = mTouchFrame;
}
final int count = getChildCount();
for (int i = count - 1; i >= 0; i--) {
final View child = getChildAt(i);
if (child.getVisibility() == View.VISIBLE) {
child.getHitRect(frame);
if (frame.contains(x, y)) {
return mFirstPosition + i;
}
}
}
return INVALID_POSITION;
}
即currentChildViewId=pointToPosition(ev.getX(),ev.getY());