前言
仍然是一個小demo,這個添加了如果中間項沒有到中間位置時,自動滾動至中間位置,并且在滑動過程中,不改變中間項
先上效果圖
源碼如下:
public class MiddleHorizal extends HorizontalScrollView {
private onMiddleItemChangedListener middleItemChangedListener;
private Handler mHandler = new Handler();
private int currentX = 0;//記錄當前滾動的距離
private int scrollDealy = 50;//滾動監聽間隔
int current = -1; //當前位于中間item的位置
double halfScreenWidth; //屏幕的一半寬度
LinearLayout content; //內容view
public MiddleHorizal(Context context, AttributeSet attrs) {
super(context, attrs);
halfScreenWidth = 1.0 * getScreenWidth(context) / 2;
}
public MiddleHorizal(Context context) {
super(context, null);
}
/**
* 滾動監聽runnable
*/
private Runnable scrollRunnable = new Runnable() {
@Override
public void run() {
if (getScrollX() == currentX) {
//滾動停止 取消監聽線程
mHandler.removeCallbacks(this);
setMiddleItem();
return;
}
else {
//手指離開屏幕 view還在滾動的時候
mHandler.postDelayed(this, scrollDealy);
}
currentX = getScrollX();
}
};
/**
* 判斷中間項 并滾動至屏幕中央
*/
private void setMiddleItem() {
if (content != null) {
int minWidth = -1;
int lastCurrent = current;
int minDivider = 0;
//判斷距離屏幕中間距離最短的item
for (int i = 0; i < content.getChildCount(); i++) {
int divider = (int) ((content.getChildAt(i).getX() + 1.0 * content.getChildAt(i).getWidth() / 2 - currentX) - halfScreenWidth);
int absDivider = Math.abs(divider);
if (minWidth < 0) {
minWidth = absDivider;
}
else if (minWidth > absDivider) {
minWidth = absDivider;
minDivider = divider;
current = i;
}
}
//如果中間項變化,則恢復原狀
if (lastCurrent != current && lastCurrent >= 0) {
TextView lastMiddleView = (TextView) content.getChildAt(lastCurrent);
lastMiddleView.setTextSize(20);
lastMiddleView.setTextColor(Color.RED);
}
//滾動至中間位置
scrollBy(minDivider, 0);
middleItemChangedListener.middleItemChanged(current);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
//手指在上面移動的時候 取消滾動監聽線程
mHandler.removeCallbacks(scrollRunnable);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//手指移動的時候
mHandler.post(scrollRunnable);
break;
}
return super.onTouchEvent(ev);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//初始化,使得中間項在屏幕中間位置
if (getChildCount() > 0 && current < 0 && middleItemChangedListener != null) {
content = (LinearLayout) getChildAt(0);
setMiddleItem();
}
}
public void setMiddleItemChangedListener(onMiddleItemChangedListener middleItemChangedListener) {
this.middleItemChangedListener = middleItemChangedListener;
}
/**
* 獲取屏幕寬度
*/
public static int getScreenWidth(Context context) {
Display display = ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
return display.getWidth();
}
/**
* 回調,將中間項位置傳遞出去
*/
interface onMiddleItemChangedListener {
void middleItemChanged(int current);
}
}
<!--中間位置做個小標記-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="1"
/>
<com.qianqian.demo.viewdemo.MiddleHorizal
android:id="@+id/horizontalScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:layout_centerVertical="true"
android:orientation="horizontal"
/>
</com.qianqian.demo.viewdemo.MiddleHorizal>
<TextView
android:id="@+id/currentItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/horizontalScrollView"
android:layout_centerHorizontal="true"
/>
public class MainActivity extends Activity implements MiddleHorizal.onMiddleItemChangedListener {
LinearLayout contentLinear;
MiddleHorizal horizontalScrollView;
private ArrayList<String> items = new ArrayList<>();
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contentLinear = (LinearLayout) findViewById(R.id.content);
textView = (TextView) findViewById(R.id.currentItem);
horizontalScrollView = (MiddleHorizal) findViewById(R.id.horizontalScrollView);
horizontalScrollView.setMiddleItemChangedListener(this);
contentLinear.removeAllViews();
for (int i = 0; i < 50; i++) {
TextView child = new TextView(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(80, ViewGroup.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER;
child.setTextSize(20);
child.setTextColor(Color.RED);
child.setGravity(Gravity.CENTER);
child.setText("" + i);
items.add(""+i);
contentLinear.addView(child, params);
}
}
@Override
public void middleItemChanged(int current) {
TextView currentTxt = (TextView) contentLinear.getChildAt(current);
currentTxt.setTextSize(24);
currentTxt.setTextColor(Color.GREEN);
String s = items.get(current);
textView.setText("位于中間位置的是" + s);
}
}
補充
添加點擊某一項,將該item移動到中間位置的事件,這樣子做:
//在自定義view中添加方法
/**
* 點擊item,將該item移動至中間位置
*
* @param v 點擊的item
*/
public void setMiddleItem(View v) {
if (v.getTag() != null && (int) v.getTag() != current) {
TextView lastMiddleView = (TextView) content.getChildAt(current);
lastMiddleView.setTextSize(20);
lastMiddleView.setTextColor(Color.RED);
int divider = (int) ((v.getX() + 1.0 * v.getWidth() / 2 - getScrollX()) - halfScreenWidth);
scrollBy(divider, 0);
current = (int) v.getTag();
middleItemChangedListener.middleItemChanged(current);
}
}
\\activity中添加子view的時候,設置tag并在click方法中調用即可
child.setTag(i);//將postion設為tag,設置位置
child.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
horizontalScrollView.setMiddleItem(v);
}
});