如何用按钮控制循环HorizontalScrollView水平滑动

如何用按钮控制循环HorizontalScrollView水平滑动

最近做了一个用按钮控制循环滚轴水平滑动的控件,在这里总结一下。

要控制滑动那么先要实现一个能够循环滚动的滚轴,以下是我的思路:
首先实现这个需求我想到的方案有两个:

第一:做一个适配器,这个适配器的主要方法是通过获取存入图片的list的长度,接着通过除余的方法循环的返回相应位置的View再添加上去。
缺点:当图片的多的时候,并且没有通过LruCache,获取采样率,压缩等方法进行处理的时候,很可能出现加载缓慢或者出现OOM情况。

第二:在初始化界面的时候,只从适配器读取少量的view加载在父容器之上。把显示的view存入一个showList的队列中,把剩下的view存入一个waitList的队列中。
滚动的时候分为两种情况,一个是向前滚动,一个向后滚动。
向前滚动:
只要getScrollx()超过了子视图的宽度位置处,执行以下动作:

如何用按钮控制循环HorizontalScrollView水平滑动_第1张图片
每一次的滑动将showList的头放到waitList的尾,waitList的头放到showList的尾。

向后滚动:
只要getScrollx()检测到是从父容器0处开始滑动,执行以下动作:
如何用按钮控制循环HorizontalScrollView水平滑动_第2张图片
每一次的滑动将showList的尾放到waitList的头,waitList的尾放到showList的头。

这样就能避免像网上那样通过记录位置,来计算子视图的位置了。

思路就能想到这么多,可能还有更棒的思路,本人才疏学浅只能想到这么多。

循环队列的思想完成之后,就开始做按钮控制滑动的工作。

那么按钮控制自定义控件HorizontalScrollView的滑动,就会想到两种设计模式,一种是通过装饰模式扩展其中的功能,另一种是通过桥接模式用自定义的按钮和原来的功能组合,控制HorizontalScrollView的功能,封装好之后暴露一个接口就能完成

这里展示桥接模式相对简单的应用方法,下面是截取部分代码:

文件MyHorizntalScrollView.java

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.IllegalFormatCodePointException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

import javax.security.auth.PrivateCredentialPermission;

import com.example.adapter.HorizontalAdapter;
import com.example.newgoldinglauncher.R;

import android.R.integer;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

public class MyHorizontalScroller extends HorizontalScrollView implements OnTouchListener,setChildViewListener{
    private static LinearLayout container;
    private static Map map = new HashMap();//每个view的编号
    private static Map containermap = new HashMap();//每个view在父容器的编号
    private int ScreenWidth;
    private int currentIndex;
    private int FirstIndex = 0;
    private static HorizontalAdapter adapter;
    private OnItemCilckListener mListener;
    private CurrentImageChangeListener cListener;
    private static LinkedList showList = new LinkedList();//子view显示列表
    private static LinkedList waitlist = new LinkedList();//子view待显示列表
    private int LastInterceptX;
    private int LastInterceptY;
    private int ChildWidth;
    private int ChildHeight;
    private static int childCountonScreen;//当前屏幕子view个数
    private LinearLayout parentLayout;
    private VelocityTracker vTracker;
    private static int firstposition;

    public interface OnItemCilckListener{
        public void onClick(View v,int pos);
    }

    public interface CurrentImageChangeListener{
        public void OnCurrentChange(int position,View v);
    }

    public MyHorizontalScroller(Context context){
        super(context);
        init(context);
    }

    public MyHorizontalScroller(Context context,AttributeSet attrs){
        super(context, attrs);
        init(context);

    }

    public MyHorizontalScroller(Context context,AttributeSet attrs,int defStyle){
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context){
        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        ScreenWidth = outMetrics.widthPixels;
        vTracker = VelocityTracker.obtain();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        container = (LinearLayout)getChildAt(0);
    }

    protected void loadNextImg(){//手动滑动,向后滑动
        //Log.e("movenext", "here");
        if(adapter.getCount() == 0){
            return;
        }
        int waittoadd = waitlist.removeFirst();
        int deleteshow = showList.removeFirst();
        showList.addLast(waittoadd);
        waitlist.addLast(deleteshow);
        int index = showList.get(childCountonScreen - 1);
        map.remove(container.getChildAt(0));
        containermap.remove(container.getChildAt(0));
        container.removeViewAt(0);
        View view = adapter.getView(index, null, container);
        container.addView(view);
        map.put(view, index);
        Log.e("index", ""+index);
//      for(Integer value : map.values()){
//          Log.e("mapvalue", ""+value);
//      }
        for(int k = 0;k < childCountonScreen;k++){
            containermap.put(container.getChildAt(k), k);
        }
        String clazz = this.getClass().getName();
        //Log.e("nextthis", ""+clazz);
        view.setOnTouchListener(this);
        //setchildviewListener();
        if(cListener != null){
            notifyCurrentImgChange();
        }
    }

    protected void loadPreImg(){//手动滑动,向前滑动
        if(adapter.getCount() == 0){
            return;
        }
        int last = container.getChildCount() - 1;
        map.remove(container.getChildAt(last));
        containermap.remove(container.getChildAt(last));
        container.removeViewAt(last);
        int waittoadd = waitlist.removeLast();
        int deleteshow = showList.removeLast();
        showList.addFirst(waittoadd);
        waitlist.addFirst(deleteshow);
        int index = showList.get(0);
        View view = adapter.getView(index, null, container);
        container.addView(view,0);
        map.put(view, index);
        for(int k = 0;k < childCountonScreen;k++){
            containermap.put(container.getChildAt(k), k);
        }
        String clazz = this.getClass().getName();
        Log.e("prethis", ""+clazz+last);
        view.setOnTouchListener(this);
        for(Integer value : map.values()){
            Log.e("mapvalue",""+value);
        }
        //setchildviewListener();
        if(cListener != null){
            notifyCurrentImgChange();
        }
    }

//  @Override
//  public boolean onInterceptTouchEvent(MotionEvent event){
//      boolean Intercept = false;
//      int x = (int)event.getX();
//      int y = (int)event.getY();
//      
//      switch (event.getAction()) {
//      case MotionEvent.ACTION_DOWN:
//          Intercept = false;
//          break;
//          
//      case MotionEvent.ACTION_MOVE:
//          int x1 = (int)event.getX();
//          int y1 = (int)event.getY();
//          int deltaX = x - x1;
//          int deltaY = y - y1;
//          if(Math.abs(deltaX) < 10 && Math.abs(deltaY) < 10){
//              Intercept = false;
//          }else {
//              Intercept = true;
//          }
//          break;
//      case MotionEvent.ACTION_UP:
//          Intercept = true;
//      default:
//          break;
//      }
//      return Intercept;
//  }



    @Override
    public boolean onTouch(View v, MotionEvent ev) {
        // TODO Auto-generated method stub
        int scrollX = getScrollX();
        vTracker.computeCurrentVelocity(1000);
        float xVelocity =  vTracker.getXVelocity();
        //Log.e("xv", ""+xVelocity);
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.e("down", "here");
            int id = 0;
            if(mListener != null){
                Log.e("mListener", "notnull"+container.getChildCount());
                for(int i = 0;i < container.getChildCount();i++){
                    container.getChildAt(i).setBackgroundColor(Color.WHITE);//将所有子view背景涂白
                }

                mListener.onClick(v,containermap.get(v));
                Log.e("hclick",""+id);
            }
            Log.e("mListener", "null");
            break;

        case MotionEvent.ACTION_MOVE:
            Log.e("scrollx", ""+scrollX);
            if(scrollX >= ChildWidth){
                Log.e("go", "h");
                loadNextImg();
            }else if(scrollX == 0){
                Log.e("back", "h");
                loadPreImg();
            }
            break;

        case MotionEvent.ACTION_UP:
            vTracker.clear();
            break;
        default:
            break;
        }
        return true;
    }



    public void initData(HorizontalAdapter adapter){
        this.adapter = adapter;
        container = (LinearLayout) getChildAt(0);
        final View view = adapter.getView(0, null, container);
        container.addView(view);
        if(ChildWidth == 0 && ChildHeight == 0){
            int w =View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            view.measure(w, h);
            ChildWidth = view.getMeasuredWidth();
            ChildHeight = view.getMeasuredHeight();
            Log.e("childwidth",""+ChildWidth);
            //childCountonScreen = (ScreenWidth/ ChildWidth == 0)?(ScreenWidth / ChildWidth) + 1:(ScreenWidth / ChildWidth) + 1;
            childCountonScreen = 9;
        }
        initScreen(childCountonScreen);
    }



    public void initScreen(int childCountonScreen){
        container = (LinearLayout) getChildAt(0);
        container.removeAllViews();
        map.clear();
        showList.clear();
        waitlist.clear();
        Log.e("countonScreen","" + childCountonScreen);
        for(int i = 0;i < childCountonScreen;i++){
            View view = adapter.getView(i, null, container);
            view.setOnTouchListener(this);
            container.addView(view);
            map.put(view, i);
            containermap.put(view, i);
            currentIndex = i;
            showList.add(i);
        }
        Log.e("count", ""+(adapter.getCount()-childCountonScreen));
        for(int i = childCountonScreen;i < adapter.getCount();i++){
            waitlist.add(i);
        }
    }

    public void notifyCurrentImgChange(){
        int first = showList.peek();
        for (int i = 0; i < container.getChildCount(); i++)
        {
            container.getChildAt(i).setBackgroundColor(Color.WHITE);
        }

        cListener.OnCurrentChange(first,container.getChildAt(0));
    }

    public void setOnClickItemListener(OnItemCilckListener mListener){
        this.mListener = mListener;
    }

    public void setOnCurrentImageChangeListener(CurrentImageChangeListener cListener){
        this.cListener = cListener;
    }

    public void PressToScroll(){
        scrollBy(ChildWidth, 0);
    }


    @Override
    protected void onDetachedFromWindow(){
        vTracker.recycle();
        super.onDetachedFromWindow();
    }

    public int getChildId(int i){
        return map.get(container.getChildAt(i));
    }

    public int getChildWidth(){
        return ChildWidth;
    }

    public View getChildView(int i){

        return container.getChildAt(i);
    }

    public int getAllCount(){
        return adapter.getCount();
    }

    public int getCount(){
        return container.getChildCount();
    }

    public int getNextNumber(View v){
        Log.e("containermap",""+containermap.get(v));
        return containermap.get(v);
    }

    public View getInitView(){
        return container.getChildAt(0);
    }

    public void setfirstposition(View v){
        int position = containermap.get(v);

        this.firstposition = position;
    }

    public int getfirstposition(){
        Log.e("fposition", ""+firstposition);
        return firstposition;
    }

    @Override
    public void setchildviewListener() {
        // TODO Auto-generated method stub
        for(int i = 0;i < childCountonScreen;i++){
            container.getChildAt(i).setOnTouchListener(this);
        }
    }

}

文件(控制滑动的按钮)MyImageView.java:

import java.util.HashMap;
import java.util.LinkedList;

import com.example.newgoldinglauncher.R;
import com.example.widget.MyHorizontalScroller.OnItemCilckListener;

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.view.View.OnTouchListener;;

public class MyImageView extends ImageView implements OnTouchListener{
    private MyHorizontalScroller horizontalScroller;
    private OnImageClickListener iListener;
    private HashMap selector = new HashMap();
    private LinkedList blueList = new LinkedList();
    private LinkedList whiteList = new LinkedList();
    private int change;
    private View selectView;//选中的view
    private static int k;
    private int fixpos = 0;
    private int startpos;

    public interface OnImageClickListener  {
        public void click(View v);
    }


    public MyImageView(Context context){
        super(context);
        horizontalScroller = new MyHorizontalScroller(context);
        this.setOnTouchListener(this);
        init();
    }

    public MyImageView(Context context,AttributeSet attrs){
        super(context, attrs);
        horizontalScroller = new MyHorizontalScroller(context, attrs);
        this.setOnTouchListener(this);
        init();
    }

    public MyImageView(Context context,AttributeSet attrs,int defStyle){
        super(context, attrs, defStyle);
        horizontalScroller = new MyHorizontalScroller(context, attrs, defStyle);
        this.setOnTouchListener(this);
        init();
    }

    public void setOnImageClickListener(OnImageClickListener iListener){
        this.iListener = iListener;
    }

    public void init(){
        horizontalScroller.setOnClickItemListener(new OnItemCilckListener() {

            @Override
            public void onClick(View v, int pos) {
                // TODO Auto-generated method stub
                v.setBackgroundColor(Color.parseColor("#AA024DA4"));
                horizontalScroller.setfirstposition(v);
            }
        });
    }



    public void NextImage(View v){//按按钮后滚轴向后移动
        int distance = horizontalScroller.getChildWidth();
        horizontalScroller.scrollBy(distance, 0);
        horizontalScroller.loadNextImg();
        k = horizontalScroller.getfirstposition();
        Log.e("k", ""+k);
        View view = horizontalScroller.getChildView(k);
        for(int i = 0;i < horizontalScroller.getCount();i++){
            horizontalScroller.getChildView(i).setBackgroundColor(Color.WHITE);
        }
        view.setBackgroundColor(Color.parseColor("#AA024DA4"));
        //selectView = view;

    }

    public void PreImage(View v){//按按钮滚轴向前移动
        int distance = horizontalScroller.getChildWidth();
        horizontalScroller.scrollBy(-distance, 0);
        int scrollx = getScrollX();
        View view;
        if(scrollx == 0){
            horizontalScroller.loadPreImg();
            view = horizontalScroller.getChildView(0);
            view.setBackgroundColor(Color.parseColor("#AA024DA4"));
        }else {
            int i = horizontalScroller.getNextNumber(v) - 1;
            if(i < 0){
                i = horizontalScroller.getCount() - 1;
            }
            view = horizontalScroller.getChildView(i);
            view.setBackgroundColor(Color.parseColor("#AA024DA4"));
        }

    }


    public void ClickImage(View v){

        if(this.getId() == R.id.previous){
            PreImage(v);
        }else if(this.getId() == R.id.next){
            NextImage(v);
        }
    }

    public void getImgId(View v){
        this.selectView = v;
    }


    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        int x1 = 0;
        int x2 = 0;
        int y1 = 0;
        int y2 = 0;
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            x1 = (int)event.getX();
            y1 = (int)event.getY();
            if(iListener != null){
                iListener.click(v);
            }
            this.setBackgroundColor(Color.parseColor("#AA024DA4"));
            for(int i = 0;i < horizontalScroller.getCount();i++){
                horizontalScroller.getChildView(i).setBackgroundColor(Color.WHITE);
            }
            selectView.setBackgroundColor(Color.parseColor("#AA024DA4"));
            break;
        case MotionEvent.ACTION_UP:
            x2 = (int)event.getX();
            y2 = (int)event.getY();
            this.setBackgroundColor(Color.parseColor("#FFFFFF"));
            ClickImage(selectView);
            break;
        default:
            break;
        }
        return true;


    }
}

MyImageView暴露了一个setOnImageClickListner的接口,只要实现其中接口,就能将耦合降低。

下面是MainActivity.java文件:

public class MainActivity extends Activity {
    private LedView ledview;
    private TextView cityname;
    private TextView tempView;
    private MyImageView previous;
    private MyImageView next;
    private HorizontalListView fountionList;
    private MyHorizontalScroller horizontalScroller;
    private HorizontalAdapter adapter;
    private int[] imgId = new int[]{R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,
            R.drawable.h,R.drawable.i,R.drawable.j,R.drawable.k};
    private HashMapselector = new HashMap();
    private static int position;
    private ArrayList imgList = new ArrayList();
    private View selectView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ledview = (LedView) findViewById(R.id.led_view);
        cityname = (TextView)findViewById(R.id.cityname);
        tempView = (TextView)findViewById(R.id.temp);
        horizontalScroller = (MyHorizontalScroller)findViewById(R.id.fountion_list);
        previous = (MyImageView)findViewById(R.id.previous);
        next = (MyImageView)findViewById(R.id.next);
        init(this);

    }

    private void init(Context context){//初始化界面
        LayoutInflater inflater = getLayoutInflater();
        for(int i = 0;i < imgId.length;i++){
            imgList.add(imgId[i]);
            Log.e("imgId",String.valueOf(imgId[i]));
        }
        adapter = new HorizontalAdapter(context, imgList);
        horizontalScroller.setOnClickItemListener(new OnItemCilckListener() {//自己编写的接口,为了将选中的view的背景变蓝
            @Override
            public void onClick(View v, int pos) {
                // TODO Auto-generated method stub
                Log.e("item", "pos"+pos);
                v.setBackgroundColor(Color.parseColor("#AA024DA4"));
                horizontalScroller.setfirstposition(v);
                selectView = v;
                position = pos;
                Log.e("position", ""+position);
            }
        });
        horizontalScroller.initData(adapter);
//      horizontalScroller.setOnCurrentImageChangeListener(new CurrentImageChangeListener() {
//          
//          @Override
//          public void OnCurrentChange(int position, View v) {
//              // TODO Auto-generated method stub
//              v.setBackgroundColor(Color.parseColor("#AA024DA4"));
//          }
//      });

        previous.setOnImageClickListener(new OnImageClickListener() {//向前滑动控件的接口

            @Override
            public void click(View v) {
                // TODO Auto-generated method stub
                Log.e("previous", "here");
                if(selectView == null){
                    selectView = horizontalScroller.getInitView();
                }else {
                    previous.getImgId(selectView);
                }

            }
        });

        next.setOnImageClickListener(new OnImageClickListener() {//向后滑动控件

            @Override
            public void click(View v) {
                // TODO Auto-generated method stub
                Log.e("next", "here");
                if(selectView == null){
                    selectView = horizontalScroller.getInitView();
                }else {
                    next.getImgId(selectView);
                }

            }
        });




    }




    @Override
    protected void onResume(){
        super.onResume();
        ledview.start();
    }

    @Override
    protected void onStop(){
        super.onStop();
        ledview.stop();
    }
}

这里面我犯了一个小错误:在控制滑动的时候声明了一个新的MyHorizontalScrollView。当时忘记了导致自己没有添加相应的监听器。最好在初始化的时候,传入原来的Horizontal,这样就能减少内存的申请,优化这个控件。

感谢鸿洋大神那一段代码对我的启发。

http://blog.csdn.net/lmj623565791/article/details/38140505

这是代码全貌地址:

https://github.com/yjy239/ComplexUI

你可能感兴趣的:(Andriod)