android scrollview居中,使用 HorizontalScrollView 实现滚动控制

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

最后的效果如下:

2066bb9c8331e4bc876bcff9deeff175.png

下面逐步上代码:

布局文件 activity_main.xml 如下:

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">

android:layout_height="wrap_content" />

android:id="@+id/hsv"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:scrollbarStyle="outsideInset">

android:id="@+id/avatar_layout"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@id/hsv"

android:layout_marginTop="12dp"

android:id="@+id/scrollx_tv"/>

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="滚动位置"/>

上面的 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 

final Map 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> lstAvatars;

private Context context;

private int layoutWidthPerAvatar;

public HSVAdapter(Context context, int layoutWidthPerAvatar){

this.context=context;

this.lstAvatars =new ArrayList>();

this.layoutWidthPerAvatar = layoutWidthPerAvatar;

}

@Override

public int getCount() {

return lstAvatars.size();

}

@Override

public Map getItem(int location) {

return lstAvatars.get(location);

}

@Override

public long getItemId(int arg0) {

return arg0;

}

public void addObject(Map 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 如下:

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="center">

android:layout_width="64dp"

android:layout_height="64dp"

android:src="@drawable/avatar"/>

android:id="@+id/index_tv"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center" />

最后看一下主页面 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 

Map map = new HashMap();

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()));

}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/498811.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python数学计算模块_Python-NumPy模块数学和统计方法(4)

1.前言使用一组数学函数对numpy数组进行操作的时候,有两种方式计算:对整个数组进行计算;对源数组的某个轴向的数据进行统计计算;2.下面是基本的数组统计方法数组统计方法3.统计函数的分类下面的所有统计方法,即可以当做…

系统鸿蒙生态链,任正非透露鸿蒙系统细节,比安卓速度快60%,两三年建好生态链...

原标题:任正非透露鸿蒙系统细节,比安卓速度快60%,两三年建好生态链华为鸿蒙系统自被曝光以来,就引起全球媒体极大关注。关于鸿蒙系统的相关细节,目前大多只限于猜测和知情人士透露的些许信息。不过,近期华为…

数值传热学陶文铨pdf_西安交大陶文铨当选“2019最美科技工作者”

未来网高校频道8月12日讯(记者 杨子健 通讯员 张玥)近日,由中央宣传部、中国科学技术协会、中华人民共和国科学技术部、中国科学院、中国工程院、国家国防科技工业局联合开展“最美科技工作者”学习宣传活动,共遴选出10位2019年“最美科技工作者”。据了…

android studio查看手机文件,在Android Studio中查看数据库文件的内容

通过ADB Shell连接到Sqlite3我没有找到任何办法在Android Studio中,但我访问数据库与远程shell,而不是每次拉文件。1-在命令提示符下转到您的platform-tools文件夹2-输入命令adb devices以获取设备列表C:\Android\adt-bundle-windows-x86_64\sdk\platfor…

python hook_python_理解篇_钩子方法的理解

大家好,我是金鱼座,一个走在测试领域这片蓝海中, 蹉跎前行的技术渣渣,唯有一直走下去,也许能改变点什么,加油!钩子方法,是一个比较奇怪的东西, 他实际上不做任何业务操作…

android layoutparams,Android LayoutParams用法解析

ViewGroup.LayoutParams介绍LayoutParams携带了子控件针对父控件的信息,告诉父控件如何放置自己LayoutParams类也只是简单的描述了宽高,宽和高都可以设置成三种值:1,一个确定的值;2,FILL_PARENT&#xff0c…

python 文本文件处理_53 Python - txt普通文件处理

今天讲的内容是关于数据文件的读写,我们都知道如果是普通的文本文件就比较简单,我们可以使用自带的open 方法打开我们的文件,可以使用read 和write进行读写回顾,我们把不同文件的操作放到不同文件里面新建一个目录txt,…

android静态类保存context,Android:静态获取Context是一个好习惯吗?

public class MyApp extends Application {private static Context context;public void onCreate(){super.onCreate();MyApp.context getApplicationContext();}public static Context getContext() {return MyApp.context;}}我使用它来在既不是活动也不是片段的类中使用Cont…

c# 计算空格宽度像素_C# WinForm,Graphics.MeasureString 计算不准确的坑

Graphics.MeasureString 可以计算出指定字符串在给定字体Font的尺寸SizeF,它的计算有坑:如果把字符串拆开成一个一个单字字符串并逐个计算尺寸,然后把Width加起来,你会发现并不一定等于完整的字符串计算出来的Width。经过一番折腾…

鸿蒙os 芯片制程,华为Mate50将如期发布,屏下镜头+鸿蒙OS,再见iPhone12

华为旗下有两个高端产品线,一个是mate一个就是P系列,这两款产品发布会一般相隔半年左右,按理说华为P50也该上日程了,可因为芯片缺货问题耽搁了,预计将会在7月份发布。安按照华为往常的新机发布节奏去看,华为…

nstimer循环引用_警惕使用NSTimer时的循环引用

使用NSTimer可能会碰到循环引用的问题。特别是当类具有NSTimer类型的成员变量,并且需要反复执行计时任务时。例如_timer [NSTimer scheduledTimerWithTimeInterval:5.0target:selfselector:selector(startCounting) userInfo:nilrepeats:YES];类有一个成员变量_tim…

html中写色块,CSS3 彩虹色块

CSS语言:CSSSCSS确定html,body {min-height: 100%;}body {background-image: url(data:image/svgxml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIPGRlZnMPHJhZGlhbEdyYW…

奎享添加自己字体_奎享雕刻软件写字操作简要说明

关于奎享雕刻软件单线字书写操作步骤的简要说明特别提醒!设备完全调试好以后再练习写字,调试好的标志是用微雕管家刀路雕刻界面能顺利画出一张........&#…

mysql load data infile 导入数据 某一列 空_Sql数据挑战赛amp;网络销售案例分析

SQL挑战赛第一期:1: 编写一个查询&#xff0c;列出员工姓名列表&#xff0c;员工每月工资超过2000美元且员工工作时间少于10个月。通过提升employee_id对结果进行排序select name from employee where salary > 2000 and months < 10 order by employee_id;2: 查询 Emplo…

哪个html标签用于定义文档的标题,在HTML中,(41)用于定义文档的标题。

Packet switching is a method of slicing __(71)__ messages into parcels called “packets,” sending the packets along different communication __(72)__ as they become available, and then reassembling the packets __(73)__they arrive at their destination. Prio…

stm32的afio初始化代码_STM32-IO-AFIO(复用功能IO和调试配置)

最近在学习STM32&#xff0c;在BZ上一篇关于的串口通信文章里有这么一段代码&#xff1a;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD| RCC_APB2Periph_AFIO,ENABLE);当初是参考开发的里子写的一直对GPIOD或上“RCC_APB2Periph_AFIO”这句话的意思没搞懂&#xff0c;通过这几…

js获取dom html元素属性,JS如何通过元素的CLASS属性得到对应的DOM对象?

非IE6,7,8可以直接用自带的属性 getElementsByClassName,如果需要考虑兼容&#xff0c;就需要自己写了。下面是自己写的&#xff1a;function getClassName(obj,sName) //-->obj是要获取元素的父级{ //-->sName是class名字if(document.getElementsByClassName){return ob…

feign调用多个服务_spring cloud各个微服务之间如何相互调用(Feign、Feign带token访问服务接口)...

1、首先先看什么是Feign。2、若其他服务的接口未做权限处理&#xff0c;参照上文第1点的博文即可。3、若其他服务的接口做了权限的处理(例如OAuth 2)时该如何访问?a、有做权限处理的服务接口直接调用会造成调用时出现http 401未授权的错误&#xff0c;继而导致最终服务的http …

html项目列表页面源码,HTML 列表

HTML 列表HTML 支持有序、无序和定义列表:HTML 列表有序列表第一个列表项第二个列表项第三个列表项无序列表列表项列表项列表项在线实例无序列表本例演示无序列表。有序列表本例演示有序列表。(可以在本页底端找到更多实例。)HTML无序列表无序列表是一个项目的列表&#xff0c;…

vue 实现数据滚动显示_vue实现动态添加数据滚动条自动滚动到底部的示例代码...

在使用vue实现聊天页面的时候&#xff0c;聊天数据动态加到页面中&#xff0c;需要实现滚动条也自动滚动到底部。这时我找到网上有个插件 vue-chat-scroll但是安装后发现是用不了的&#xff0c;报错信息如下&#xff1a;VM14383:27 [Vue warn]: Failed to resolve directive: c…