公司以前的Camera项目使用了Gallery,该控件存在问题,有些偶现Bug无法解决。比如 狂点+滑动 会偶现错乱。Gallery原生方法未加锁同步,又不可重写,导致该Bug不可控。
当用户点击又滑动的时候,下面这两个方法就一起调用,偶现Position错乱
mGalleryView.setOnItemClickListener(new OnItemClickListener());
mGalleryView.setSelection(mCurrentIndex);
既然这样,那就从新实现有Gallery效果的控件
效果:可以点击切换,也可以外部布局切换。
首先实现下图中的自定义textView实现选中缩放效果。
public class AnimaTextView extends TextView
{
private AnimatorSet scaleTextAnimator;
public AnimaTextView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
public AnimaTextView(Context context, AttributeSet attrs)
{
this(context, attrs,0);
}
public AnimaTextView(Context context)
{
this(context,null);
}
private void init()
{
if (this.scaleTextAnimator == null)
{
this.scaleTextAnimator = new AnimatorSet();
ObjectAnimator localObjectAnimator1 = ObjectAnimator.ofFloat(this, "ScaleX", new float[] { 1.0F, 1.05F });
localObjectAnimator1.setDuration(500);
ObjectAnimator localObjectAnimator2 = ObjectAnimator.ofFloat(this, "ScaleY", new float[] { 1.0F, 1.05F });
localObjectAnimator2.setDuration(500);
this.scaleTextAnimator.play(localObjectAnimator2).with(localObjectAnimator1);
}
}
@Override
public void setSelected(boolean selected)
{
super.setSelected(selected);
if(selected)
{
scaleTextAnimator.start();
}else
{
setScaleX(1.0F);
setScaleY(1.0F);
}
}
}
然后写放置AnimaTextView 的ViewGroup。
public class JScrollParentView extends LinearLayout implements OnClickListener
{
private AnimaTextView[] mItemView = null;
private CharSequence[] itemsEntry = null;
private int mItemSpace = 36;
private Context mContext = null;
private int mItemsCount = -1;
private ColorStateList textColor;
private float textSize = 14;
private OnItemSelected mOnItemSelcted = null;
private TextView mCurrentView = null;
private int mCurrentPosition = 0;
public interface OnItemSelected
{
void onItemSelected(int position);
}
public JScrollParentView(Context context)
{
this(context,null);
}
public JScrollParentView(Context context, AttributeSet attrs)
{
this(context, attrs,0);
}
public JScrollParentView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.JScrollParentView);
itemsEntry = ta.getTextArray(R.styleable.JScrollParentView_item_texts);
mItemSpace = ta.getDimensionPixelSize(R.styleable.JScrollParentView_item_space, 36);
textColor = ta.getColorStateList(R.styleable.JScrollParentView_item_texts_colors);
textSize = ta.getFloat(R.styleable.JScrollParentView_item_texts_size, 12f);
mItemsCount = itemsEntry.length;
ta.recycle();
setOrientation(HORIZONTAL);
setGravity(Gravity.LEFT);
setPadding(0, 0, 0, 0);
mContext = context;
initView();
}
private void initView()
{
if (mItemsCount > 0)
{
mItemView = new AnimaTextView[mItemsCount];
for (int i = 0; i < mItemsCount; i++)
{
LayoutParams itemParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
AnimaTextView item = new AnimaTextView(mContext);
item.setTextColor(textColor);
item.setTextSize(textSize);
item.setText(itemsEntry[i].toString());
item.setGravity(Gravity.CENTER);
item.setId(i);
item.setShadowLayer(1, 0, 0, 0x50000000);
item.setOnClickListener(this);
// if(i != 0)
{
itemParams.leftMargin = mItemSpace;
}
addView(item,itemParams);
mItemView[i] = item;
}
}
}
@Override
public void onClick(View v)
{
if(mOnItemSelcted != null)
{
if(mCurrentView != null && mCurrentPosition != v.getId())
{
mOnItemSelcted.onItemSelected(v.getId());
}
}
}
public int getLeftPointX(int position)
{
if(position > mItemsCount -1 || mItemsCount <1)
{
return 0;
}
int paddingLeft = 0;
for(int i = position; i >= 0; i--)
{
int itemWidth = getChildAt(i).getMeasuredWidth();
if( i == position)
{
paddingLeft = paddingLeft + itemWidth/2 + mItemSpace; //最后一个是itemWidth/2 + mItemSpace,以后都是itemWidth + mItemSpace
}else
{
paddingLeft = paddingLeft + itemWidth + mItemSpace;
}
}
return paddingLeft;
}
public void setOnItemSelectedListener(OnItemSelected listener)
{
mOnItemSelcted = listener;
}
public void updateSelcted(int position)
{
if(mCurrentView != null)
{
mCurrentView.setSelected(false);
}
mCurrentView = mItemView[position];
mCurrentPosition = position;
mCurrentView.setSelected(true);
}
}
public class JScrollPanelLayout extends FrameLayout implements OnItemSelected ,OnGestureListener
{
private int mLeftStart = 0;
private JScrollParentView mItemLayout = null;
private int mCurrentPosition =2;
private int mItemCount = -1;
private int mWidth = 0;
private int mDisplayWith;
private Context mContext = null;
private GestureDetector mDetector = null;
private static final int SLIDE_MIN_PIXCEL = 25;
public JScrollPanelLayout(Context context)
{
this(context,null);
// TODO Auto-generated constructor stub
}
public JScrollPanelLayout(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
mContext = context;
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mDisplayWith = wm.getDefaultDisplay().getWidth();
mDetector = new GestureDetector(context,this);
}
public JScrollPanelLayout(Context context, AttributeSet attrs)
{
this(context, attrs,0);
// TODO Auto-generated constructor stub
}
@Override
protected void onFinishInflate()
{
// TODO Auto-generated method stub
super.onFinishInflate();
mItemLayout = (JScrollParentView)findViewById(R.id.scroll_item);
mItemLayout.setOnItemSelectedListener(this);
mWidth = getWidth();
mItemCount = mItemLayout.getChildCount();
//caculateLeftStart();
}
//每次通过动态改变mLeftStart,进行滑动
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
if(mItemLayout != null)
{
mItemLayout.layout(mLeftStart,mItemLayout.getTop(), mLeftStart + mItemLayout.getWidth(), mItemLayout.getBottom());
}
}
//计算mLeftStart , mItemLayout.updateSelcted(mCurrentPosition)修改选中View
public void caculateLeftStart()
{
if(mWidth == 0)
{
mWidth = mDisplayWith;
}
int nextLeftStart = 0;
if(mItemLayout != null)
{
nextLeftStart = mWidth/2 - mItemLayout.getLeftPointX(mCurrentPosition);//确定中心位置
}
ValueAnimator anim = ValueAnimator.ofInt(mLeftStart, nextLeftStart);
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
mLeftStart = (Integer) animation.getAnimatedValue();
requestLayout();
mItemLayout.updateSelcted(mCurrentPosition);
}
});
anim.start();
}
@Override
public void onItemSelected(int position)
{
if(mCurrentPosition != position)
{
mCurrentPosition = position;
caculateLeftStart();
}
}
@Override
public boolean onDown(MotionEvent e)
{
// TODO Auto-generated method stub
return true;
}
@Override
public void onShowPress(MotionEvent e)
{
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e)
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent e)
{
// TODO Auto-generated method stub
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
doFling(e1,e2,velocityX,velocityY);
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
// TODO Auto-generated method stub
return mDetector.onTouchEvent(event);
}
//e1:手势起点的移动事件
//e2: 当前手势点的移动事件
//velocityX:每秒x轴方向移动的像素
//velocityY: 每秒y轴方向移动的像素
public void doFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
if(Math.abs(e1.getX() - e2.getX()) > Math.abs(e1.getY() - e2.getY())){
if (e1.getX() - e2.getX() > SLIDE_MIN_PIXCEL) {
if(mCurrentPosition != mItemCount -1)
{
onItemSelected(mCurrentPosition +1);
}
} else if (e1.getX() - e2.getX() < -SLIDE_MIN_PIXCEL) {
if(mCurrentPosition != 0)
{
onItemSelected(mCurrentPosition - 1);
}
}
}
}
}
使用:
public class CenterIndicatorActivity extends Activity implements OnGestureListener
{
private JScrollPanelLayout mJScrollPanelLayout;
private GestureDetector mDetector = null;
@Override
protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.center_indicator_activity);
mJScrollPanelLayout = (JScrollPanelLayout)findViewById(R.id.scroll_parent);
mJScrollPanelLayout.postDelayed(new Runnable(){
@Override
public void run()
{
mJScrollPanelLayout.caculateLeftStart();
mJScrollPanelLayout.setVisibility(View.VISIBLE);
}}, 300);
mDetector = new GestureDetector(this, this);
}
@Override
public boolean onDown(MotionEvent e)
{
// TODO Auto-generated method stub
return true;
}
@Override
public void onShowPress(MotionEvent e)
{
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e)
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent e)
{
// TODO Auto-generated method stub
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
mJScrollPanelLayout.doFling(e1, e2, velocityX, velocityY);
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
// TODO Auto-generated method stub
return mDetector.onTouchEvent(event);
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:jpower="http://schemas.android.com/apk/res/com.jimmy.jpower"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.jimmy.jpower.widget.centerIndicator.JScrollPanelLayout
android:id="@+id/scroll_parent"
android:layout_width="match_parent"
android:layout_height="48dip"
android:visibility="invisible"
android:layout_centerInParent="true"
android:background="@color/tab_bg">
<com.ws.jpower.widget.centerIndicator.JScrollParentView
android:id="@+id/scroll_item"
android:layout_width="match_parent"
android:layout_height="48dip"
jpower:item_space="18dp"
jpower:item_texts="@array/jpower_center_list"
jpower:item_texts_size="14"
jpower:item_texts_colors="@color/text_color">
</com.ws.jpower.widget.centerIndicator.JScrollParentView>
</com.ws.jpower.widget.centerIndicator.JScrollPanelLayout>
</RelativeLayout>
<array name="jpower_center_list">
<item>Video</item>
<item>Photo</item>
<item>Beauty</item>
<item>Pano</item>
</array>