使用 HorizontalScrollView 实现滚动控制

发布时间:2020-08-05 14:20:46 作者:安静的疯子
来源:网络 阅读:6897

功能要求是屏幕上固定显示 3 个 Layout 项(图片+文字),支持点击切换到选择的 Layout 项,并支持滑动切换到最近的 Layout 项。


最后的效果如下:


使用 HorizontalScrollView 实现滚动控制

 

下面逐步上代码:

 

布局文件 activity_main.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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView android:text="" android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    
    <HorizontalScrollView
        android:id="@+id/hsv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbarStyle="outsideInset">
        <cn.steven.hsvp_w_picpathswitch.HSVLayout
            android:id="@+id/avatar_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </HorizontalScrollView>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/hsv"
        android:layout_marginTop="12dp"
        android:id="@+id/scrollx_tv"/>
    <Button
        android:onClick="onClickScrollX"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/scrollx_tv"
        android:layout_marginTop="12dp"
        android:text="滚动位置"/>
</RelativeLayout>

 

上面的 HorizontalScrollView 中使用了自定义的 HSVLayout 布局,定义(HSVLayout.java)如下:

 

public class HSVLayout extends LinearLayout {

    private HSVAdapter adapter;
    private Context context;

    public HSVLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    /**
     * 设置布局适配器
     *
     * @param layoutWidthPerAvatar 指定了每一个 item 的占用宽度
     * @param adapter 适配器
     * @param notify 在点击某一个 item 后的回调
     */
    public void setAdapter(int layoutWidthPerAvatar, HSVAdapter adapter,
                           final INotifySelectItem notify) {
        this.adapter = adapter;

        for (int i = 0; i < adapter.getCount(); i++) {
            final Map<String, Object> map = adapter.getItem(i);
            View view = adapter.getView(i, null, null);

            // 为视图设定点击监听器
            final int finalI = i;
            view.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 点击选择了某一个 Item 视图
                    notify.select(finalI);
                }
            });

            this.setOrientation(HORIZONTAL);

            // 设置固定显示的每个 item 布局的宽度
            this.addView(view, new LinearLayout.LayoutParams(
                    layoutWidthPerAvatar, LayoutParams.WRAP_CONTENT));
        }
    }
}

 

HSVLayout 中的每一个 视图 item 都是由 HSVAdapter 进行设置的,这个比较简单,只控制了每一个 item 的展示,不影响整个水平滚动视图:

 

public class HSVAdapter extends BaseAdapter {

    private static final String TAG = "HSV";

    private List<Map<String,Object>> lstAvatars;
    private Context context;
    private int layoutWidthPerAvatar;

    public HSVAdapter(Context context, int layoutWidthPerAvatar){
        this.context=context;
        this.lstAvatars =new ArrayList<Map<String,Object>>();
        this.layoutWidthPerAvatar = layoutWidthPerAvatar;
    }
    @Override
    public int getCount() {
        return lstAvatars.size();
    }

    @Override
    public Map<String,Object> getItem(int location) {
        return lstAvatars.get(location);
    }

    @Override
    public long getItemId(int arg0) {
        return arg0;
    }

    public void addObject(Map<String,Object> map){
        lstAvatars.add(map);
        notifyDataSetChanged();
    }

    @Override
    public View getView(int location, View arg1, ViewGroup arg2) {
        View view = LayoutInflater.from(context).inflate(R.layout.user_avatar,null);
        view.setLayoutParams(new ViewGroup.LayoutParams(layoutWidthPerAvatar,
                ViewGroup.LayoutParams.WRAP_CONTENT));
        TextView tvIndex = (TextView) view.findViewById(R.id.index_tv);
        tvIndex.setText("index-" + String.valueOf(location));
        return view;
    }
}

 

其对应的布局文件 user_avatar.xml 如下:

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">
    <ImageView
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:src="@drawable/avatar"/>
    <TextView
        android:id="@+id/index_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center" />
</LinearLayout>

 

最后看一下主页面 MainActivity:

 

public class MainActivity extends ActionBarActivity
    implements INotifySelectItem {

    private static final String TAG = "Main";

    private HorizontalScrollView hsv;
    private HSVLayout layoutAvatar;
    private HSVAdapter adapterAvatar;

    private TextView tvScrollX;

    private int layoutWidthPerAvatar = 0;

    private Integer[] p_w_picpaths = {
            R.drawable.avatar,
            R.drawable.avatar,
            R.drawable.avatar,
            R.drawable.avatar,
            R.drawable.avatar,
            R.drawable.avatar,
            R.drawable.avatar,
            R.drawable.avatar,
            R.drawable.avatar
    };

    // 记录当前居中的头像索引
    private int currentIndex = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int width = DisplayUtil.getScreenWidth(this);
        int layoutWidth = (int) (width - getResources().getDimension(R.dimen.activity_horizontal_margin) * 2);

        // 每一个头像占用的宽度
        layoutWidthPerAvatar = layoutWidth / 3;

        hsv = (HorizontalScrollView) findViewById(R.id.hsv);
        hsv.setOnTouchListener(new View.OnTouchListener() {

            private int lastScrollX = 0;
            private int TouchEventId = -9987832;

            Handler handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    if (msg.what == TouchEventId) {
                        if (lastScrollX == hsv.getScrollX()) {
                            // 停止滚动,计算合适的位置(采用四舍五入)
                            int indexScrollTo = Math.round(lastScrollX/(layoutWidthPerAvatar*1.0f));
                            Log.d(TAG, "stop scroll - " + lastScrollX
                                    + "|" + layoutWidthPerAvatar
                                    + "|" + lastScrollX/(layoutWidthPerAvatar*1.0f)
                                    + "|" + indexScrollTo);
                            if (indexScrollTo > 0) {
                                hsv.smoothScrollTo(indexScrollTo*layoutWidthPerAvatar, 0);
                            } else {
                                hsv.smoothScrollTo(0, 0);
                            }
                        } else {
                            handler.sendMessageDelayed(
                                    handler.obtainMessage(TouchEventId), 100);
                            lastScrollX = hsv.getScrollX();
                        }
                    }
                }
            };

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.d(TAG, "touch event - action: " + event.getAction()
                        + "|" + event.getX()
                        + "|" + event.getY()
                        + "|" + hsv.getScrollX()
                        + "|" + hsv.getScrollY());
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    handler.sendMessageDelayed(handler.obtainMessage(TouchEventId), 100);
                }
                return false;
            }
        });

        layoutAvatar = (HSVLayout) findViewById(R.id.avatar_layout);
        adapterAvatar = new HSVAdapter(this, layoutWidthPerAvatar);
        for (int i = 0; i < p_w_picpaths.length; i++) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("p_w_picpath", p_w_picpaths[i]);
            map.put("index", (i+1));
            adapterAvatar.addObject(map);
        }
        layoutAvatar.setAdapter(layoutWidthPerAvatar, adapterAvatar, this);

        tvScrollX = (TextView) findViewById(R.id.scrollx_tv);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void select(int position) {
        Toast.makeText(this, "select " + String.valueOf(position),
                Toast.LENGTH_SHORT).show();
        if (position > 0) {
            if (currentIndex != position) {
                hsv.smoothScrollTo((position-1)*layoutWidthPerAvatar, 0);
                currentIndex = position;
            }
        }
    }

    public void onClickScrollX(View view) {
        tvScrollX.setText("Scroll.x = " + String.valueOf(hsv.getScrollX()));
    }
}

 

推荐阅读:
  1. actionbar、slidingmenu、ViewPager的使用 day04
  2. 怎么在android studio中使用Spinner实现一个下拉菜单

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

horizontalscrollview

上一篇:区块链是什么

下一篇:学习Java语言的优势有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》