高德地图SDK Android版开发 10 InfoWindow

高德地图SDK Android版开发 10 InfoWindow

  • 前言
  • 相关类和方法
    • 默认样式
      • Marker类
      • AMap类
      • AMap.OnInfoWindowClickListener 接口
    • 自定义样式(视图)
      • AMap 类
      • AMap.ImageInfoWindowAdapter 接口
    • 自定义样式(Image)
      • AMap.ImageInfoWindowAdapter 接口
  • 示例
    • 界面布局
    • MapInfoWindow类
      • 常量
      • 成员变量
      • 初始化
      • 创建与移除覆盖物
      • 设置属性
      • 自定义样式
      • 加载与移除地图
    • MapInfoWindowActivity 类
      • 控件响应事件
    • 运行效果图

前言

前文介绍高德地图添加Marker覆盖物的使用方法,Marker结合InfoWindow可展示更详尽的信息。本文将介绍以下内容:

  1. 使用SDK默认样式显示InfoWindow的方法;
  2. 自定义InfoWindow样式的方法。

相关类和方法

默认样式

  • 在高德地图SDK中,InfoWindow 是点标记的一部分,默认的 Infowindow 只显示 Marker 对象的两个属性,一个是 title 和另一个 snippet。
  • SDK 为用户提供了默认的 InfoWindow 样式,调用 Marker 类的 showInfoWindow() hideInfoWindow() 方法可以控制显示和隐藏。
  • 当改变 Markertitlesnippet 属性时,再次调用 showInfoWindow(),可以更新 InfoWindow 显示内容。

Marker类

  • 标题、文字片段和附加信息的方法
类型方法说明
StringgetSnippet()获取Marker 覆盖物的文字片段。
StringgetTitle()获取Marker 覆盖物的标题。
ObjectgetObject()获取Marker覆盖物的附加信息对象,即自定义的Marker的属性。
voidsetSnippet(String snippet)设置Marker 覆盖物的文字片段。
voidsetTitle(String title)设置Marker 覆盖物的标题。
voidsetObject(Object object)设置Marker覆盖物的附加信息对象。
  • InfoWindow的方法
类型方法说明
booleanisInfoWindowEnable()获取Marker覆盖物是否允许InfoWindow显示,
可以通过 Marker.setInfoWindowEnable(boolean) 进行设置
voidsetInfoWindowEnable(boolean enabled)设置Marker覆盖物的InfoWindow是否允许显示,默认为true。
设置为false之后, 调用Marker.showInfoWindow() 将不会生效
booleanisInfoWindowShown()返回Marker覆盖物的信息窗口是否显示,true: 显示,false: 不显示。
voidshowInfoWindow()显示 Marker 覆盖物的信息窗口。
voidhideInfoWindow()隐藏Marker覆盖物的信息窗口。

AMap类

类型方法说明
voidsetOnInfoWindowClickListener(AMap.OnInfoWindowClickListener listener)设置marker的信息窗口点击事件监听接口。

AMap.OnInfoWindowClickListener 接口

public interface OnInfoWindowClickListener {void onInfoWindowClick(Marker marker);
}

自定义样式(视图)

AMap 类

类型方法说明
voidsetInfoWindowAdapter(AMap.InfoWindowAdapter adapter)设置marker的信息窗口定制接口。

AMap.ImageInfoWindowAdapter 接口

用来定制Marker的信息窗口。

类型方法说明
android.view.ViewgetInfoWindow(Marker marker)定制展示marker信息的View。(注:可自定义背景
android.view.ViewgetInfoContents(Marker marker)定制展示marker信息的View。(注:使用默认背景
public interface InfoWindowAdapter {// 如果返回的View不为空且View的background不为null,则直接使用它来展示marker的信息。// 如果backgound为null,SDK内部会给这个View设置一个默认的background。// 如果这个方法返回null,内容将会从getInfoContents(Marker)方法获取。View getInfoWindow(Marker marker);// 如果返回的View不为空且View的background不为null,则直接使用它来展示marker的信息。// 如果backgound为null,SDK内部会给这个View设置一个默认的background。// 如果这个方法返回null,将使用内置的一个默认的View来展示marker的信息。View getInfoContents(Marker marker);
}

触发机制

  • 默认情况下,当单击某个marker时,如果该marker的Title和Snippet不为空,则会触发getInfoWindow和getInfoContents回调。
  • 另外,通过**调用Marker.showInfoWindow()**同样可以触发上面两个回调。

返回null的处理逻辑

  • 自5.2.1开始,如果getInfoWindow(Marker) 和 getInfoContents(Marker) 均返回null,将不展示InfoWindow的信息

自定义样式(Image)

说明:此方法官方指南未介绍,来自参考手册。(未做验证)

AMap.ImageInfoWindowAdapter 接口

«interface»
InfoWindowAdapter
«interface»
ImageInfoWindowAdapter
+long getInfoWindowUpdateTime()

用途:

用来实现marker与对应InfoWindow同步移动。

默认情况下,InfoWindow是一个View, 拖动地图的时候由于View 布局较慢,会有延迟的效果

为了解决此问题,新增AMap.ImageInfoWindowAdapter, InfoWindow会被转为图片,拖动地图时会跟随Marker

注意

使用ImageInfoWindowAdapter后InfoWindow作为View本身的功能被减弱,比如动态更新图片,播放Gif图片等等均无法使用。

如果想要动态的去更新infowindow内容,请务必仔细看看此接口的更新机制

更新机制

设置此接口返回值之后,会定期(默认周期无穷大)调用一个 getInfoWindow(Marker)将View转换为图片

由于将View转成图片会比较耗时,不能一直调用,而设置时间间隔可以减少一定的耗时。

调用Marker.showInfoWindow() 也可以触发调用 AMap.InfoWindowAdapter.getInfoWindow(Marker) 并将View转换为图片。

类型方法说明
longgetInfoWindowUpdateTime()自定义整个信息窗口属性间隔时间。单位为 ms

方法说明

  • 如果返回值 小于或等于 0,则认为是无穷大。
  • 如果返回值 (0,100] , 则认为是100(如果频繁将View转成图片,内存抖动会很严重,建议这个值不要太低)。
  • 如果这个想实现更小的时间间隔或者不想受这个接口约束,可以保持返回默认值,并自行设置计时器。

示例

界面布局

在这里插入图片描述

  • 布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="MapInfoWindowActivity"><com.amap.api.maps.MapViewandroid:id="@+id/map"android:layout_width="match_parent"android:layout_height="0dp"app:layout_constraintBottom_toTopOf="@id/bottomView"app:layout_constraintTop_toTopOf="parent" /><androidx.appcompat.widget.LinearLayoutCompatandroid:id="@+id/bottomView"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintTop_toBottomOf="@id/map"><RadioGroupandroid:id="@+id/RadioGroup"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@android:color/background_dark"android:gravity="center_horizontal"android:orientation="horizontal"android:paddingHorizontal="10dp"><RadioButtonandroid:id="@+id/simpleMode"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:checked="true"android:onClick="setMarkerFlag"android:text="简单"android:textColor="@color/white"android:textStyle="bold" /><RadioButtonandroid:id="@+id/adapter_window_mode"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:onClick="setMarkerFlag"android:text="适配器(窗口)"android:textColor="@color/white"android:textStyle="bold" /><RadioButtonandroid:id="@+id/adapter_content_mode"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:onClick="setMarkerFlag"android:text="适配器(内容)"android:textColor="@color/white"android:textStyle="bold" /></RadioGroup></androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>

MapInfoWindow类

  • 以下是MapInfoWIndows部分代码

常量

public static final String SIMPlE_MODE = "SimpleMode";
public static final String ADAPTER_WINDOW_MODE = "AdapterWindowMode";
public static final String ADAPTER_CONTENT_MODE = "AdapterContentMode";

成员变量

// 覆盖物列表
List<BaseOverlay> overlays = new ArrayList<>();
// 选中的状态
String selectedFlag = SIMPlE_MODE;
// 气泡图标
ArrayList<BitmapDescriptor> bitmaps = new ArrayList<>();

初始化

int[] drawableIds = BubbleIcons.Number;
for (int drawableId : drawableIds) {BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(drawableId);bitmaps.add(bitmap);
}
initEvent();
private void initEvent() {// 设置marker的信息窗口点击事件监听接口。map.setOnInfoWindowClickListener(new AMap.OnInfoWindowClickListener() {@Overridepublic void onInfoWindowClick(Marker marker) {// 隐藏Marker覆盖物的信息窗口。marker.hideInfoWindow();}});
}

创建与移除覆盖物

public void addMarkers() {// 构造大量坐标数据List<LatLng> points = new ArrayList<>();points.add(new LatLng(39.97923, 116.357428));points.add(new LatLng(39.94923, 116.397428));points.add(new LatLng(39.97923, 116.437428));points.add(new LatLng(39.92353, 116.490705));points.add(new LatLng(40.023537, 116.289429));points.add(new LatLng(40.022211, 116.406137));// 创建OverlayOptions的集合ArrayList<MarkerOptions> optionsList = new ArrayList<>();for (int i = 0; i < points.size(); ++i) {// 创建OverlayOptions属性MarkerOptions option = new MarkerOptions().position(points.get(i)).icon(bitmaps.get(i)).title("标题" + (i + 1)).snippet("详细信息" + (i + 1));// 将OverlayOptions添加到listoptionsList.add(option);}boolean moveToCenter = true;// 在地图上添一组图片标记(marker)对象,// 并设置是否改变地图状态以至于所有的marker对象都在当前地图可视区域范围内显示。ArrayList<Marker> newOverlays = map.addMarkers(optionsList, moveToCenter);overlays.addAll(newOverlays);
}public void removeOverlay() {// 从地图上删除所有的覆盖物(marker,circle,polyline 等对象),// 但myLocationOverlay(内置定位覆盖物)除外。
//        boolean isKeepMyLocationOverlay = true;
//        map.clear(isKeepMyLocationOverlay);for (BaseOverlay overlay : overlays) {if (overlay instanceof Marker) {Marker marker = (Marker) overlay;marker.hideInfoWindow();}}overlays.clear();
}

设置属性

public void setFlag(String flag) {selectedFlag = flag;switch (selectedFlag) {case SIMPlE_MODE:map.setInfoWindowAdapter(null);break;case ADAPTER_WINDOW_MODE:map.setInfoWindowAdapter(new WindowModeAdapter());break;case ADAPTER_CONTENT_MODE:map.setInfoWindowAdapter(new ContentModeAdapter());break;}
}

说明:自定义样式参考官方Demo,WindowModeAdapterContentModeAdapter为自定义两个适配器。代码和布局见附录。

自定义样式

  • WindowModeAdapter

布局custom_info_window.xml (background+image+tItle+snippet)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="100dp"android:layout_height="100dp"android:background="@drawable/custom_info_bubble"android:orientation="horizontal"><ImageViewandroid:id="@+id/badge"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginRight="5dp" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:ellipsize="end"android:singleLine="true"android:textColor="#ff000000"android:textSize="14dp"android:textStyle="bold" /><TextViewandroid:id="@+id/snippet"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ellipsize="end"android:singleLine="true"android:textColor="#ff7f7f7f"android:textSize="14dp" /></LinearLayout></LinearLayout>

WindowModeAdapter

private class WindowModeAdapter implements AMap.InfoWindowAdapter {@Overridepublic View getInfoWindow(Marker marker) {// 加载自定义布局文件作为InfoWindow的样式View view = LayoutInflater.from(context).inflate(R.layout.custom_info_window, null);render(marker, view);return view;}@Overridepublic View getInfoContents(Marker marker) {return null;}
}
  • ContentModeAdapter

布局custom_info_contents.xml (image+tItle+snippet)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><ImageViewandroid:id="@+id/badge"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginRight="5dp"android:adjustViewBounds="true" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:ellipsize="end"android:singleLine="true"android:textColor="#ff000000"android:textSize="14dp"android:textStyle="bold" /><TextViewandroid:id="@+id/snippet"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ellipsize="end"android:singleLine="true"android:textColor="#ff7f7f7f"android:textSize="14dp" /></LinearLayout></LinearLayout>

ContentModeAdapter

private class ContentModeAdapter implements AMap.InfoWindowAdapter {@Overridepublic View getInfoWindow(Marker marker) {return null;}@Overridepublic View getInfoContents(Marker marker) {// 加载自定义布局文件作为InfoWindow的样式View view = LayoutInflater.from(context).inflate(R.layout.custom_info_contents, null);render(marker, view);return view;}
}
  • render方法(设置image+title+snippet)
private void render(Marker marker, View view) {ImageView imageView = view.findViewById(R.id.badge);imageView.setImageResource(android.R.drawable.ic_menu_gallery);String title = marker.getTitle();TextView titleUi = view.findViewById(R.id.title);if (title != null) {SpannableString titleText = new SpannableString(title);titleText.setSpan(new ForegroundColorSpan(Color.RED), 0, titleText.length(), 0);titleUi.setTextSize(15);titleUi.setText(titleText);} else {titleUi.setText("");}String snippet = marker.getSnippet();TextView snippetUi = view.findViewById(R.id.snippet);if (snippet != null) {SpannableString snippetText = new SpannableString(snippet);snippetText.setSpan(new ForegroundColorSpan(Color.GREEN), 0, snippetText.length(), 0);snippetUi.setTextSize(20);snippetUi.setText(snippetText);} else {snippetUi.setText("");}
}

加载与移除地图

public void onMapLoaded() {addMarkers();setFlag(SIMPlE_MODE);
}public void onMapDestroy() {removeOverlay();for (BitmapDescriptor bitmap : bitmaps) {bitmap.recycle();}bitmaps = null;
}

MapInfoWindowActivity 类

  • 以下是MapInfoWindowActivity类部分代码

控件响应事件

public void setMarkerFlag(View view) {boolean checked = ((RadioButton) view).isChecked();if (!checked)return;int id = view.getId();String flag;if (id == R.id.simpleMode)flag = MapInfoWindow.SIMPlE_MODE;else if (id == R.id.adapter_window_mode)flag = MapInfoWindow.ADAPTER_WINDOW_MODE;else if (id == R.id.adapter_content_mode)flag = MapInfoWindow.ADAPTER_CONTENT_MODE;elsereturn;mapInfoWindow.setFlag(flag);
}

运行效果图

简单适配器(窗口)适配器(内容)
在这里插入图片描述在这里插入图片描述在这里插入图片描述
默认样式自定义:
background+image+title+snippet
自定义:
image+title+snippet

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

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

相关文章

【数学建模国赛思路预约】2024全国大学生数学建模竞赛助攻思路、代码、论文

2024年全国大学生数学建模大赛马上就要开始了&#xff0c;大家有没有准备好呢&#xff0c;今年将会和之前一样&#xff0c;将会在比赛赛中时期为大家提供比赛各题的相关解题思路、可运行代码参考以及成品论文。 一、分享计划表如下所示 1、 赛中分享内容包括&#xff08;2023国…

高并发内存池(二):​整体框架的介绍与ThreadCache的实现

目录 整体框架介绍 ThreadCache的主体框架 自由链表-FreeList 内存对齐-RoundUp 计算桶位置-Index 基础版 进阶版 线程局部存储 __declspec(thread) 关键字 实现线程无锁 申请内存-Allocate 释放内存-Deallocate 从中心缓存中申请内存 整体框架介绍 高并发内存池…

机器学习引领未来:赋能精准高效的图像识别技术革新

图像识别技术近年来取得了显著进展,深刻地改变了各行各业。机器学习,特别是深度学习的突破,推动了这一领域的技术革新。本文将深入探讨机器学习如何赋能图像识别技术,从基础理论到前沿进展,再到实际应用与挑战展望,为您全面呈现这一领域的最新动态和未来趋势。 1. 引言 …

kubernetes集群部署Confluence 7.2.0+mysql 5.7(自测有效)

背景介绍&#xff1a; Confluence是一个专业的企业知识管理与协同软件。使用简单&#xff0c;但它强大的编辑和站点管理特征能够帮助团队成员之间共享信息、文档协作、集体讨论&#xff0c;信息推送。 这里介绍的使用的是Confluence 7.2.0版本的。 一、在kubernetes集群部署 1…

本地零阶提示优化

本文探讨了如何优化大型语言模型&#xff08;LLM&#xff09;中的提示&#xff08;prompt&#xff09;&#xff0c;以更有效地利用这些黑盒模型的能力。传统的优化方法倾向于寻找全局最优解&#xff0c;但在某些情况下这种做法可能表现不佳。通过对提示优化进行深入的研究&…

01 Docker概念和部署

目录 1.1 Docker 概述 1.1.1 Docker 的优势 1.1.2 镜像 1.1.3 容器 1.1.4 仓库 1.2 安装 Docker 1.2.1 配置和安装依赖环境 1.3镜像操作 1.3.1 搜索镜像 1.3.2 获取镜像 1.3.3 查看镜像 1.3.4 给镜像重命名 1.3.5 存储&#xff0c;载入镜像和删除镜像 1.4 Doecker…

汽车功能安全--TC3xx之PBIST、MONBIST

目录 1.PMS 电源监控速览 2.PBIST 3.MONBIST 4.小结 1.PMS 电源监控速览 英飞凌TC3xx芯片的四种硬件机制&#xff0c;分别是&#xff1a; PMS:PBIST: Power Built-in Self Test. MCU:LBIST: Logic Built-in Self Test. PMS:MONBIST: Monitor Built-in Self Test. VMT:MBI…

史上最全的Linux常用命令汇总(超全面!超详细!)收藏这一篇就够了!

command &#xff1a;命令名&#xff0c;相应功能的英文单词或单词的缩写[-options] &#xff1a;选项&#xff0c;可用来对命令进行控制&#xff0c;也可以省略parameter &#xff1a;传给命令的参数&#xff0c;可以是 零个、一个 或者 多个 查阅命令帮助信息 -help 说明&…

【高阶数据结构】B树、B+树、B*树

B树、B树、B*树 1. 常见的搜索结构2. B树概念3. B树的插入分析4. B树的插入实现4.1 B树的节点设计4.2 B树的部分插入实现14.3 B树的查找4.4 B树的部分插入实现24.5 插入key的过程4.7 B树的插入完整代码4.8 B树的简单验证4.9 B树的删除4.10 B树的性能分析 5. B树6. B*树7. 总结8…

【C++】STL学习——list模拟实现

目录 list介绍list结构介绍节点类的实现迭代器的实现构造函数运算符重载--运算符重载运算符重载!运算符重载*运算符重载->运算符重载 const迭代器的实现多参数模板迭代器list函数接口总览默认成员函数构造函数1构造函数2构造函数3 析构函数拷贝构造函数赋值重载函数 迭代器b…

开放式系统互连(OSI)模型的实际意义

0 前言 开放式系统互连&#xff08;OSI&#xff0c;Open Systems Interconnection&#xff09;模型&#xff0c;由国际标准化组织&#xff08;ISO&#xff09;在1984年提出&#xff0c;目的是为了促进不同厂商生产的网络设备之间的互操作性。 定义了一种在层之间进行协议实现…

【C++】STL容器详解【下】

目录 一、list容器 1.1 list基本概念 1.2 lsit构造函数 1.3 list数据元素插入和删除操作 1.4 list大小操作 1.5 list赋值操作 1.6 list数据的存取 1.7 list反转排序 二、set/multiset容器 2.1 set/multiset基本概念 2.2 set构造函数 2.3 set赋值操作 2.4 set大小操…

数据库的操作:SQL语言的介绍

一.前言 SQL是一种结构化查询语言。关系型数据库中进行操作的标准语言。 二.特点 ①对大小写不敏感 例如&#xff1a;select与Select是一样的 ②结尾要使用分号 没有分号认为还没结束; 三.分类 ①DDL&#xff1a;数据定义语言&#xff08;数据库对象的操作&#xff08;结…

| Origin绘图 |瀑布图的绘制(保姆级教程)

&#x1f411; | Origin绘图 |瀑布图的绘制&#x1f411; 文章目录 &#x1f411; | Origin绘图 |瀑布图的绘制&#x1f411;前言瀑布图简介瀑布图绘制数据导入坐标轴刻度调节调整画布大小添加颜色及设置线条为曲线坐标轴标签调节网格调节 总结 前言 感觉好久没出过关于Origin…

MyBatis-MappedStatement什么时候生成?QueryWrapper如何做到动态生成了SQL?

通过XML配置的MappedStatement 这部分MappedStatement主要是由MybatisXMLMapperBuilder进行解析&#xff0c;核心逻辑如下&#xff1a; 通过注解配置的MappedStatement 核心逻辑就在这个里面了&#xff1a; 继承BaseMapper的MappedStatement 我们看看这个类&#xff0c;里…

FreeRTOS学习笔记—③RTOS内存管理篇(待更新完善)

二、RTOS的核心功能 RTOS的核心功能块主要分为任务管理、内核管理、时间管理以及通信管理4部分&#xff0c;框架图如下所示&#xff1a; &#xff08;1&#xff09;任务管理&#xff1a;负责管理和调度任务的执行&#xff0c;确保系统中的任务能够按照预期运行。 &#xff08;…

了解开源消息代理RabbitMQ

1.RabbitMQ 是什么&#xff1f; RabbitMQ是一个消息代理:它接受并转发消息。你可以把它想象成邮局:当你把要寄的邮件放进邮箱时&#xff0c;你可以确定邮递员最终会把邮件送到收件人那里。在这个比喻中&#xff0c;RabbitMQ是一个邮筒、一个邮局和一个邮递员。RabbitMQ和邮局之…

【kubernetes】配置管理中心Configmap运用

一&#xff0c;介绍 Configmap&#xff08;简写 cm&#xff09;是k8s中的资源对象&#xff0c;用于保存非机密性的配置的&#xff0c;数据可以用key/value键值对的形式保存&#xff0c;也可通过文件的形式保存。 【局限性】&#xff1a;在ConfigMap不是用来保存大量数据的&am…

(计算机网络)运输层

一.运输层的作用 运输层&#xff1a;负责将数据统一的交给网络层 实质&#xff1a;进程在通信 TCP&#xff08;有反馈&#xff09;UDP&#xff08;无反馈&#xff09; 二.复用和分用 三. TCP和UDP的特点和区别 进程号--不是固定的 端口号固定--mysql--3306 端口--通信的终点 …

【深度学习】softmax 回归的从零开始实现与简洁实现

前言 小时候听过一个小孩练琴的故事&#xff0c;老师让他先弹最简单的第一小节&#xff0c;小孩练了两天后弹不出。接着&#xff0c;老师让他直接去练更难的第二小节&#xff0c;小孩练习了几天后还是弹不出&#xff0c;开始感觉到挫败和烦躁了。 小孩以为老师之后会让他从简…