自定义城市列表之——自定义字母索引,包含历史城市存储

          转载请注明出处:http://blog.csdn.net/lxlyhm/article/details/52049321

          自定义城市列表 相信大家都很常见,特别是在这两年非常受欢迎的在线旅游软件上(途牛旅游,驴妈妈旅游等)城市列表是不可或缺的一个模块,先上图看效果

                                                          

           点击搜索栏,输入搜索关键字,首字母,拼音:

                                

          首先分析界面需求,搭建布局。此界面主要被我分成5部分:

          第一部分是头部标题栏部分,此处可以任意使用自定义标题栏也好,简单布局也好,只要能实现就可以,我在此处使用简单布局;

          第二部分是搜索栏部分,此部分引用普通布局,设置布局背景drawable/shape_layout即可;

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <corners  android:radius="5dp"/>
    <solid android:color="#ffffff"/>
</shape>
          第三部分是自定义View字母索引部分,自定义一个类MyView1继承View,上代码,相信注释都写得比较清晰了

public class MyView1 extends View
{

	private Paint mPaint;//初始画笔
	private int right;//覆盖画布右边范围
	private int index;//下标
	private boolean ispress;//是否触碰点击
	private Paint touchPaint;//触碰点击画笔
	//如果json文件无数据  初始化数据和字母
	private ArrayList<String> letterList = new ArrayList<String>();
	String[] letters = new String[]{"#","A","B","C","D","E","F","G","H",
			"I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W",
			"X","Y","Z"};
	//构造方法
	public MyView1(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		
		initPaint();//新建画笔
		initLetter();//初始化静态数据
	}
	
	//如果json文件无数据  初始化字母
	public void initLetter()
	{
		for (int i = 0; i < letters.length; i++)
		{
			letterList.add(letters[i]);
		}
	}
	
	// 新建画笔
	public void initPaint()
	{
		//默认文本
		mPaint = new Paint();
		mPaint.setStyle(Paint.Style.STROKE);//设置风格
		mPaint.setColor(Color.parseColor("#ff999999"));// 设置颜色
		mPaint.setTextSize((int) this.getResources().getDimension(R.dimen.city_textSize));//小手机
		mPaint.setTextAlign(Align.CENTER);//设置文本的对齐方式
		//触摸按下文本
		touchPaint = new Paint();
		touchPaint.setStyle(Paint.Style.STROKE);//设置风格
		touchPaint.setColor(Color.parseColor("#ffaf0000"));// 设置颜色
		touchPaint.setTextSize((int) this.getResources().getDimension(R.dimen.city_textSize_pre));//小手机
		touchPaint.setTextAlign(Align.CENTER);//设置文本的对齐方式
	}
	
	//canvas画布
	@Override
	protected void onDraw(Canvas canvas)
	{
		super.onDraw(canvas);
		if (ispress)
		{
			canvas.drawARGB(100, 100, 100, 100);
		}
		canvas.translate(0, 28);//起始位置   绝对位移
		int width = canvas.getWidth();//画布宽度
		int height = canvas.getHeight();//画布高度
		//画默认文本
		for (int i = 0; i < letterList.size(); i++)
		{
			//平均分成几份,即每一个字母的高度=总高度/总份数
			int h = height/letterList.size();
			//按下  即触碰
			if (index == i && ispress)
			{
				canvas.drawText(letterList.get(i), width/2, h*i+5, touchPaint);
			}else
			{
				//没按下
				canvas.drawText(letterList.get(i), width/2, h*i+5, mPaint);
			}
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		float y = event.getY();//获得手指触摸的Y轴坐标
		float c = event.getX();//获得手指触摸的X轴坐标
		//获得按下文本的下标=触摸处的高度/每一份的高度
		index = (int) (y/(getHeight()/letterList.size()));
		if (index >= letterList.size())
		{
			index = letterList.size() -1;
		}
		if (index < 0)
		{
			index = 0;
		}
		//捕获手指的动作    按下  滑动   抬起
		switch (event.getAction())
		{
		case MotionEvent.ACTION_DOWN://按下
			ispress = true;
			listener.OnLetterTouch(letterList.get(index));
			break;
		case MotionEvent.ACTION_MOVE://移动
			ispress = true;
			listener.OnLetterTouch(letterList.get(index));
			break;
		case MotionEvent.ACTION_UP://抬起
			ispress = false;
			listener.OnLetterUp();
			break;
		default:
			break;
		}
		
		invalidate();
		return true;
	}
	//添加字母
	public void setLetters(ArrayList<String> list)
	{
		letterList.clear();
		letterList.addAll(list);
		invalidate();
	}
	
	//声明接口变量
	OnLetterListener listener;
	//定义监听方法
	public void setOnLetterListener(OnLetterListener l)
	{
		listener = l;
	}
	//定义接口
	public interface OnLetterListener
	{
		void OnLetterTouch(String letter);
		void OnLetterUp();
	}
	
}

            第四部分是普通列表部分,此处可以灵活使用RecyclerView或者ListView,我简单使用ListView,此部分可以用一个listview直接add三个头部即可;

由于热门城市也是一个列表,所有需要用listview的item是一个listview,即listview嵌套listview,使用过类似功能的小伙伴们肯定有过嵌套之后子listview显示不完全的情况发生,所有此处需要自定义一个listiew重新计算高度,作为主listview的头部添加作子listview,代码如下所示:

public class MyListView1 extends ListView {

	public MyListView1(Context context, AttributeSet attrs) {

		super(context, attrs);

	}

	public MyListView1(Context context) {

		super(context);

	}

	public MyListView1(Context context, AttributeSet attrs, int defStyle) {

		super(context, attrs, defStyle);

	}

	@Override
	public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,

		MeasureSpec.AT_MOST);

		super.onMeasure(widthMeasureSpec, expandSpec);

	}

}

             第五部分是搜索列表部分,此处也可以灵活使用RecyclerView或者ListView,我简单使用ListView;

            分析完页面需求部分以后便可以根据需求搭建布局了,此处我把所有城市显示列表的listview、城市搜索显示列表的listview和自定义字母索引view放入一个帧布局,方便显示隐藏操作,布局代码如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="35dp" >

        <ImageView
            android:id="@+id/city_close"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="10dp"
            android:src="@drawable/btn_close" />

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="定位城市"
            android:textSize="15sp"
            android:textColor="@color/color_af0000"
            android:textAppearance="?android:attr/textAppearanceLarge" />

    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/relativeLayout_serch"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#e0e0e0"
        android:padding="5dp" >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:background="@drawable/shape_layout"
            android:gravity="center" >

            <EditText
                android:id="@+id/et_city_search"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toRightOf="@+id/image_search_city"
                android:background="@null"
                android:ems="10"
                android:singleLine="true"
                android:textSize="13sp"
                android:textColor="#999999"
                android:cursorVisible="false"
                android:hint=" 请输入城市中文或拼音" />

            <ImageView
                android:id="@+id/image_search_city"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:src="@drawable/btn_search_gray" />

        </RelativeLayout>
    </RelativeLayout>

    <FrameLayout
        android:id="@+id/FrameLayout1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <ListView
            android:id="@+id/listView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="none" >
        </ListView>

        <com.example.util.MyView1
            android:id="@+id/myView1"
            android:layout_width="40dp"
            android:layout_gravity="right"
            android:layout_height="wrap_content" />

        <ListView
            android:id="@+id/listView2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ffffff"
            android:visibility="gone" >
        </ListView>

    </FrameLayout>

</LinearLayout>

         接下去就可以根据布局和业务逻辑敲代码了,所有代码如下所示( 此处有用到一个城市列表数据,这里提供给大家我存放在七牛云的虚拟城市列表数据):

        

public class CityActivity extends Activity implements OnClickListener
{

	// 保存城市首字母
	private ArrayList<String> list = new ArrayList<String>();
	// 保存搜索城市信息
	private ArrayList<CityData> searchList = new ArrayList<CityData>();
	// 保存所有城市信息
	private ArrayList<CityData> cityList = new ArrayList<CityData>();
	// 保存热门城市信息
	private ArrayList<CityData> hotCityList = new ArrayList<CityData>();
	private MyView1 myView1;//自定义字母索引
	private ListView allCityListView;//所有城市ListView
	private MyAllCityAdater myAdater;//适配器
	private String letter;//字段
	private MyListView1 head_hot_listview;//自定义热门城市listview,防止listview嵌套listview滑动冲突
	String url = "http://7xtycp.com1.z0.glb.clouddn.com/cities.txt";//网址

	private HotCityAdater HotCityAdater;//热门城市适配器
	private ImageView image_city_back;
	private ListView searchListView;//城市搜索listview
	private MySearchAdater mySearchAdater;
	private EditText et_city_search;

	private TextView tv_location;
	private MyGridView mGridView;//最近访问
	private GridAdater gridAdater;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.city_activity);
		
		initUI();
		//TODO 城市定位
		initLocation();//此处定位使用百度地图,如有不懂请自行查阅百度地图API
	}

	private void initUI()
	{
		myView1 = (MyView1) findViewById(R.id.myView1);
		allCityListView = (ListView) findViewById(R.id.listView1);
		searchListView = (ListView) findViewById(R.id.listView2);
		image_city_back = (ImageView) findViewById(R.id.city_close);
		// ListView 添加三个HeaderView:定位、历史、热门 (必须在适配器之前)
		View location = getLayoutInflater().inflate(R.layout.city_heard_location, null);
		tv_location = (TextView) location.findViewById(R.id.tv_location);
		
		View recent = getLayoutInflater().inflate(R.layout.city_heard_recent, null);
		mGridView = (MyGridView) recent.findViewById(R.id.city_recent_gridview);
		
		View hotcity = getLayoutInflater().inflate(R.layout.city_heard_hotcity, null);
		head_hot_listview = (MyListView1) hotcity.findViewById(R.id.head_hot_listview);
		
		allCityListView.addHeaderView(location,null,false);
		allCityListView.addHeaderView(recent,null,false);
		allCityListView.addHeaderView(hotcity,null,false);

		myAdater = new MyAllCityAdater();
		mySearchAdater = new MySearchAdater();
		HotCityAdater = new HotCityAdater();
		gridAdater = new GridAdater();
		
		mGridView.setAdapter(gridAdater);
		searchListView.setAdapter(mySearchAdater);
		head_hot_listview.setAdapter(HotCityAdater);
		allCityListView.setAdapter(myAdater);

		myView1.setLetters(list);
		list.add("定位");
		list.add("历史");
		list.add("热门");
		myView1.setOnLetterListener(new OnLetterListener()
		{
			@Override
			public void OnLetterUp()
			{
			}

			@Override
			public void OnLetterTouch(String letter)
			{
				// TODO 点击自动跳到指定首字母位置的城市
				int position = -1;
				if (letter.equals("定位"))
				{
					position = 0;
				} else if (letter.equals("历史"))
				{
					position = 1;
				} else if (letter.equals("热门"))
				{
					position = 2;
				} else
				{
					for (int i = 0; i < cityList.size(); i++)
					{
						String upperCase = cityList.get(i).getPinyin().substring(0, 1).toUpperCase();
						if (upperCase.equals(letter))
						{
							position = i + 3;
							break;
						}
					}
				}
				allCityListView.setSelection(position);
			}
		});
		//异步任务下载
		new JsonAsync().execute(url);
		// 城市搜索
		et_city_search = (EditText) findViewById(R.id.et_city_search);
		et_city_search.addTextChangedListener(new TextWatcher()
		{

			@Override
			public void onTextChanged(CharSequence s, int start, int before, int count)
			{
				String key = s.toString();
				if ("".equals(key))
				{
					searchListView.setVisibility(View.GONE);
				} else
				{
					searchListView.setVisibility(View.VISIBLE);
				}
				searchList.clear();
				mySearchAdater.notifyDataSetChanged();
				for (int i = 0; i < cityList.size(); i++)
				{
					CityData cityData = cityList.get(i);
					if (cityData.getPinyin().startsWith(key.toLowerCase()) || cityData.getName().startsWith(key))
					{
						searchList.add(cityData);
						mySearchAdater.notifyDataSetChanged();
					}
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count, int after)
			{
			}

			@Override
			public void afterTextChanged(Editable s)
			{
			}
		});
		
		allCityListView.setOnItemClickListener(new OnItemClickListener()
		{

			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id)
			{
				int count= allCityListView.getHeaderViewsCount();	
				CityData cityData = cityList.get(position-count);
				//TODO  返回结果给首页面
				Intent intent = new Intent();
				intent.putExtra("city", cityData.getName());
				setResult(1,intent);
				finish();
			}
		});
		
		head_hot_listview.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				Intent intent=new Intent();
				intent.putExtra("city", hotCityList.get(position).getName());
				setResult(1,intent);
				finish();
			}
		});
		searchListView.setOnItemClickListener(new OnItemClickListener()
		{

			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id)
			{
				CityData cityData = searchList.get(position);
				Intent intent=new Intent();
				intent.putExtra("city", cityData.getName());
				setResult(1,intent);
				finish();
			}
		});
		mGridView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				Intent intent=new Intent();
				intent.putExtra("city", hotCityList.get(position).getName());
				setResult(1,intent);
				finish();
			}
		});
		
		image_city_back.setOnClickListener(this);
	}

	public MyLocationListenner myListener = new MyLocationListenner();
	private LocationClient mLocClient;
	private void initLocation()
	{
		// 定位初始化
		mLocClient = new LocationClient(this);
		mLocClient.registerLocationListener(myListener);
		LocationClientOption option = new LocationClientOption();
		option.setOpenGps(true); // 打开gps
		option.setCoorType("bd09ll"); // 设置坐标类型
		option.setScanSpan(1000);
		option.setAddrType("all");
		mLocClient.setLocOption(option);
		mLocClient.start();
	}
	
	/**
	 * 定位SDK监听函数
	 */
	public class MyLocationListenner implements BDLocationListener {

		@Override
		public void onReceiveLocation(BDLocation location)
		{
			String city = location.getCity();
			if (city==null)
			{
				tv_location.setText("定位失败");
			}else
			{
				tv_location.setText(city);
			}
		}

		public void onReceivePoi(BDLocation poiLocation) {
		}
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
//		 退出时销毁定位
		if (mLocClient != null)
		{
			mLocClient.stop();
		}
	}

	class JsonAsync extends AsyncTask<String, Void, String>
	{

		@Override
		protected String doInBackground(String... params)
		{
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			String result = "";
			InputStream is = null;
			try
			{
				URL url = new URL(params[0]);
				is = url.openStream();
				int len = 0;
				byte[] buffer = new byte[1024];
				while (-1 != (len = is.read(buffer)))
				{
					baos.write(buffer, 0, len);
				}
				result = new String(baos.toByteArray());
				baos.flush();

			} catch (MalformedURLException e)
			{
				e.printStackTrace();
			} catch (IOException e)
			{
				e.printStackTrace();
			} finally
			{
				if (is != null)
				{
					try
					{
						is.close();
					} catch (IOException e)
					{
						e.printStackTrace();
					}
				}
			}
			return result;
		}

		@Override
		protected void onPostExecute(String result)
		{
			super.onPostExecute(result);
			paraJson(result);
		}
	}

	// 解析文件数据
		public void paraJson(String result)
		{
			// 解析JSONObject数据 得到JSONObject对象
			try
			{
				JSONObject object = new JSONObject(result);
				// 解析JSONObject数据 得到JSONObject对象
				JSONArray jsonArray = object.getJSONArray("allcity");
				for (int i = 0; i < jsonArray.length(); i++)
				{
					JSONObject jsonObject = jsonArray.getJSONObject(i);
					// 通过key获得key值
				String name = jsonObject.getString("name");
				String pinyin = jsonObject.getString("pinyin");
				cityList.add(new CityData(name, pinyin));
				letter = pinyin.substring(0, 1).toUpperCase();
				if (!list.contains(letter))
				{
					list.add(letter);
				}
			}
			JSONArray jsonArray1 = object.getJSONArray("hotcity");
			for (int i = 0; i < jsonArray1.length(); i++)
			{
				JSONObject jsonObject1 = jsonArray1.getJSONObject(i);
				// 通过key获得值
				String name = jsonObject1.getString("name");
				hotCityList.add(new CityData(name, null));
			}
			myView1.setLetters(list);
			HotCityAdater.notifyDataSetChanged();
			myAdater.notifyDataSetChanged();
			gridAdater.notifyDataSetChanged();
		} catch (JSONException e)
		{
			e.printStackTrace();
		}
	}

	class ViewHolder
	{
		TextView tv_cityname;
		TextView tv_first;
		public RelativeLayout relativeLayout1;
	}

	//主listview适配器
	class MyAllCityAdater extends BaseAdapter
	{

		@Override
		public int getCount()
		{
			return cityList.size();
		}

		@Override
		public Object getItem(int position)
		{
			return null;
		}

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

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		{
			View layout = null;
			ViewHolder holder = null;
			if (convertView == null)
			{
				holder = new ViewHolder();
				layout = getLayoutInflater().inflate(R.layout.city_list_item, null);
				holder.tv_cityname = (TextView) layout.findViewById(R.id.tv_cityname);
				holder.tv_first = (TextView) layout.findViewById(R.id.tv_first_zimu);
				holder.relativeLayout1 = (RelativeLayout) layout.findViewById(R.id.relativeLayout1);
				layout.setTag(holder);
			} else
			{
				layout = convertView;
				holder = (ViewHolder) layout.getTag();
			}
			CityData cityData = cityList.get(position);
			// 得到前一行首字母
			String first = cityData.getPinyin().substring(0, 1).toUpperCase();
			if (position == 0)
			{
				holder.tv_first.setText(first);
				holder.tv_first.setVisibility(View.VISIBLE);
				holder.relativeLayout1.setVisibility(View.VISIBLE);
			} else
			{
				// 得到前一行首字母
				String prefirst = cityList.get(position - 1).getPinyin().substring(0, 1).toUpperCase();
				if (prefirst.equals(first))
				{
					holder.tv_first.setVisibility(View.GONE);
					holder.relativeLayout1.setVisibility(View.GONE);
				} else
				{
					holder.tv_first.setText(first);
					holder.tv_first.setVisibility(View.VISIBLE);
					holder.relativeLayout1.setVisibility(View.VISIBLE);
				}
			}
			holder.tv_cityname.setText(cityData.getName());
			return layout;
		}
	}

	//搜索的listview适配器
	class MySearchAdater extends BaseAdapter
	{

		@Override
		public int getCount()
		{
			return searchList.size();
		}

		@Override
		public Object getItem(int position)
		{
			return null;
		}

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

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		{
			View layout = null;
			ViewHolder holder = null;
			if (convertView == null)
			{
				holder = new ViewHolder();
				layout = getLayoutInflater().inflate(R.layout.city_list_item, null);
				holder.tv_cityname = (TextView) layout.findViewById(R.id.tv_cityname);
				holder.tv_first = (TextView) layout.findViewById(R.id.tv_first_zimu);
				holder.relativeLayout1 = (RelativeLayout) layout.findViewById(R.id.relativeLayout1);
				layout.setTag(holder);
			} else
			{
				layout = convertView;
				holder = (ViewHolder) layout.getTag();
			}
			holder.tv_first.setVisibility(View.GONE);
			holder.relativeLayout1.setVisibility(View.GONE);
			CityData searchData = searchList.get(position);
			holder.tv_cityname.setText(searchData.getName());
			return layout;
		}
	}
	
	class GridAdater extends BaseAdapter
	{

		@Override
		public int getCount()
		{
			return hotCityList.size();
		}

		@Override
		public Object getItem(int arg0)
		{
			return null;
		}

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

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		{
			View view = getLayoutInflater().inflate(R.layout.city_recent_gridview_item, null);
			TextView tv_recent_item = (TextView) view.findViewById(R.id.tv_recent_item);
			CityData hotcityData = hotCityList.get(position);
			tv_recent_item.setText(hotcityData.getName());
			return view;
		}

	}
	
	public class NoScrollGridView extends GridView
	{
		public NoScrollGridView(Context context)
		{
			super(context);

		}

		public NoScrollGridView(Context context, AttributeSet attrs)
		{
			super(context, attrs);
		}

		@Override
		protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
		{
			int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
			super.onMeasure(widthMeasureSpec, expandSpec);
		}
	}
	
	//TODO 热门城市listview
	class HotCityAdater extends BaseAdapter
	{

		@Override
		public int getCount()
		{
			return hotCityList.size();
		}

		@Override
		public Object getItem(int arg0)
		{
			return null;
		}

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

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		{
			View view = getLayoutInflater().inflate(R.layout.city_hotcity_list_item, null);
			TextView tv_hotcity = (TextView) view.findViewById(R.id.tv_hotcity);
			CityData hotcityData = hotCityList.get(position);
			tv_hotcity.setText(hotcityData.getName());
			return view;
		}
	}

	@Override
	public void onClick(View v)
	{
		switch (v.getId())
		{
		case R.id.city_close:
			finish();
			break;
		default:
			break;
		}
	}
}
          此处只是用最原始的异步任务解析Json数据,大家也可以换成http、okhttp等常用开源框架解析

          欢迎指正和优化~


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值